我使用以下技术来处理登录,身份验证和授权目的: 春季启动 Spring Security Oauth2 jwt令牌(在一个端口3032本地运行) Angular-5是前端(端口4200在本地)
请找到以下配置文件
Application.class
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
application.properties
server.port: 3032
spring.datasource.driverClassName=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5433/CommandCenter
spring.datasource.username=postgres
spring.datasource.password=admin
spring.jpa.generate-ddl=true
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=none
#Application specific
authentication.oauth.clientid=springSecurityClient
authentication.oauth.secret=P@ssw0rd
authentication.oauth.tokenValidityInSeconds=86400
spring.datasource.testOnBorrow=true
spring.datasource.validationQuery=SELECT 1
OAuth2ResourceServerConfig.class
@Configuration
@EnableResourceServer
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Autowired
private CustomAuthenticationEntryPoint customAuthenticationEntryPoint;
@Autowired
private CustomLogoutSuccessHandler customLogoutSuccessHandler;
@Override
public void configure(HttpSecurity http) throws Exception {
http.exceptionHandling()
.authenticationEntryPoint(customAuthenticationEntryPoint)
.and()
.logout()
.logoutUrl("/oauth/logout")
.logoutSuccessHandler(customLogoutSuccessHandler)
.and()
.csrf()
.requireCsrfProtectionMatcher(
new AntPathRequestMatcher("/oauth/authorize"))
.disable().headers().frameOptions().disable().and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests().antMatchers("/registration")
.hasRole(Authority.Admin.name()).antMatchers("/users")
.hasRole(Authority.User.name());
}
}
OAuth2AuthorizationServerConfig.class
@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends
AuthorizationServerConfigurerAdapter implements EnvironmentAware {
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
private static final String ENV_OAUTH = "authentication.oauth.";
private static final String PROP_CLIENTID = "clientid";
private static final String PROP_SECRET = "secret";
private static final String PROP_TOKEN_VALIDITY_SECONDS = "tokenValidityInSeconds";
private RelaxedPropertyResolver propertyResolver;
@Override
public void configure(ClientDetailsServiceConfigurer clients)
throws Exception {
clients.inMemory()
.withClient(propertyResolver.getProperty(PROP_CLIENTID))
.scopes("read", "write")
.autoApprove(true)
.authorities(Authorities.ROLE_Admin.name(),
Authorities.ROLE_User.name())
.authorizedGrantTypes("password", "refresh_token")
.secret(propertyResolver.getProperty(PROP_SECRET))
.accessTokenValiditySeconds(
propertyResolver.getProperty(
PROP_TOKEN_VALIDITY_SECONDS, Integer.class,
1800));
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer(),
accessTokenConverter()));
endpoints.tokenStore(tokenStore()).tokenEnhancer(tokenEnhancerChain)
.accessTokenConverter(accessTokenConverter())
.authenticationManager(authenticationManager);
}
@Bean
public TokenEnhancer tokenEnhancer() {
return new CustomTokenEnhancer();
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(
new ClassPathResource("jwt.jks"),
"JjbGllbnRfaWQiOiJyYWppdGhhcHAiLC".toCharArray());
converter.setKeyPair(keyStoreKeyFactory.getKeyPair("jwt"));
return converter;
}
@Override
public void setEnvironment(Environment environment) {
this.propertyResolver = new RelaxedPropertyResolver(environment,
ENV_OAUTH);
}
}
网络安全配置
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Bean
public DaoAuthenticationProvider authProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService);
authProvider.setPasswordEncoder(passwordEncoder());
return authProvider;
}
@Autowired
public void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.authenticationProvider(authProvider());
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring();
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
CORS过滤器配置
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class SimpleCorsFilter implements Filter {
public SimpleCorsFilter() {
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
Enumeration<String> headerNames = request.getHeaderNames();
if (headerNames != null) {
while (headerNames.hasMoreElements()) {
System.out.println("Header: " + request.getHeader(headerNames.nextElement()));
}
}
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Origin, x-requested-with, Content-Type, Accept, Authorization");
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void destroy() {
}
}
前端角度为
login() {
if(this.auth.username && this.auth.password) {
this.loginButton = true;
this.LoginUnauthorized = false;
this.authenticationService.login(this.auth.username, this.auth.password)
.subscribe(
data => {
if (data) {
this.cookieService.set('access_token', data.access_token);
this.cookieService.set('refresh_token', data.refresh_token);
this.cookieService.set('jti', data.jti);
this.cookieService.set('token_type',data.token_type)
this.cookieService.set('scope',data.scope);
this.cookieService.set('loginUser',this.auth.username);
this.authenticationService.getLoggedInUserRoles().subscribe(
data => console.log(data),
err => console.log(err)
);
}
},
error => {
this.LoginUnauthorized = true
this.auth.username ="" , this.auth.password = "";
this.loginButton = false;
});
}
}
login(username: string, password: string) {
let headers = new HttpHeaders();
var urlBase = 'http://localhost:3032/oauth/token?grant_type=password&username=' + username +'&password=' + password;
headers = headers.append('Authorization', 'Basic ' + btoa('springSecurityClient' + ':' + 'P@ssw0rd'));
return this.http.post<any>(urlBase, {username, password}, {headers:headers})
.map(res => {
return res;
});
}
getLoggedInUserRoles() {
var urlBase = 'http://localhost:3032/AuthUser/';
return this.http.get<any>(urlBase);
}
来到我的prbm是
登录但登录后需要通过
获取角色列表http://localhost:4200/AuthUser
我在浏览器中遇到以下错误,再次重定向到登录页面请帮我解决此问题。
HttpErrorResponse {headers: HttpHeaders, status: 200, statusText: "OK", url: "http://localhost:3032/login", ok: false, …}
error
:
{error: SyntaxError: Unexpected token < in JSON at position 0 at JSON.parse (<anonymous>) at XMLHttp…, text: "<html><head><title>Login Page</title></head><body …b-f01c9e439632" />↵</table>↵</form></body></html>"}
headers
:
HttpHeaders {normalizedNames: Map(0), lazyUpdate: null, lazyInit: ƒ}
message
:
"Http failure during parsing for http://localhost:3032/login"
name
:
"HttpErrorResponse"
ok
:
false
status
:
200
statusText
:
"OK"
url
:
"http://localhost:3032/login"
__proto__
:
HttpResponseBase
尝试直接访问 localhost:3032 时可以获得角色
在SoapUI中,我可以看到如下错误
{&#34; timestamp&#34;:1515303716945,&#34; status&#34;:403,&#34; error&#34;: &#34;禁止&#34;,&#34;消息&#34;:&#34;无法验证提供的CSRF令牌 因为找不到您的会话。&#34;,&#34;路径&#34;:&#34; / AuthUser&#34; }