【发布时间】:2019-01-12 04:35:05
【问题描述】:
我的身份验证过滤器未按请求启动。
我有 2 种安全配置,一种仅用于登录端点,使用 AuthenticationFromCredentialsFilter 过滤器进行身份验证,另一种用于其他端点,使用 AuthenticationFromTokenFilter 过滤器进行身份验证。
我希望调用过滤器的 attemptAuthentication 方法,但实际上没有。
在过滤器中而不是在登录控制器中更喜欢验证凭据并创建令牌有什么意义?
登录控制器现在存在,但它不应该存在,因为它的工作应该由过滤器完成。
我在安全配置中分别设置了它们:
@EnvProd
@EnableWebSecurity
@ComponentScan(nameGenerator = PackageBeanNameGenerator.class, basePackages = { "com.thalasoft.user.rest.security", "com.thalasoft.user.rest.filter" })
public class WebSecurityConfiguration {
@Order(1)
@Configuration
public class CredentialsConfiguration extends WebSecurityConfigurerAdapter {
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
public AuthenticationFromCredentialsFilter authenticationFromCredentialsFilter() throws Exception {
AuthenticationFromCredentialsFilter authenticationFromCredentialsFilter = new AuthenticationFromCredentialsFilter();
authenticationFromCredentialsFilter.setAuthenticationManager(authenticationManagerBean());
return authenticationFromCredentialsFilter;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/api/users/login")
.addFilterBefore(authenticationFromCredentialsFilter(), UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.antMatchers("/api/users/login").permitAll()
.anyRequest().authenticated();
}
}
@Order(2)
@Configuration
public class TokenConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private AuthenticationFromTokenFilter authenticationFromTokenFilter;
@Autowired
private RESTAuthenticationEntryPoint restAuthenticationEntryPoint;
@Autowired
private SimpleCORSFilter simpleCORSFilter;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable();
http
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http
.headers()
.cacheControl().disable()
.frameOptions().disable();
http
.httpBasic()
.authenticationEntryPoint(restAuthenticationEntryPoint);
http
.addFilterBefore(simpleCORSFilter, UsernamePasswordAuthenticationFilter.class);
http
.addFilterBefore(authenticationFromTokenFilter, UsernamePasswordAuthenticationFilter.class);
http.antMatcher("/api/**")
.addFilterBefore(authenticationFromTokenFilter(), UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/error").permitAll()
.antMatchers("/admin/**").hasRole(UserDomainConstants.ROLE_ADMIN)
.anyRequest().authenticated();
}
}
}
这是两个过滤器:
public class AuthenticationFromCredentialsFilter extends UsernamePasswordAuthenticationFilter {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private TokenAuthenticationService tokenAuthenticationService;
@Autowired
CredentialsService credentialsService;
@Override
public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res)
throws AuthenticationException {
try {
CredentialsResource credentialsResource = new ObjectMapper().readValue(req.getInputStream(),
CredentialsResource.class);
return authenticationManager.authenticate(credentialsService.authenticate(credentialsResource));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
Authentication authentication) throws IOException, ServletException {
tokenAuthenticationService.addTokenToResponseHeader(response, authentication);
}
}
public class AuthenticationFromTokenFilter extends UsernamePasswordAuthenticationFilter {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private TokenAuthenticationService tokenAuthenticationService;
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
tokenAuthenticationService.authenticate(request);
return authenticationManager.authenticate(tokenAuthenticationService.authenticate(request));
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
Authentication authentication) throws IOException, ServletException {
}
}
下面是一个登录请求示例,应该由安全配置中的AuthenticationFromCredentialsFilter 过滤器捕获,但未被捕获,因此允许继续到控制器并给出具有201 状态的响应:
$ curl -i -H "Accept:application/json" -H "Content-Type: application/json" "http://localhost:8080/api/users/login" -X POST -d "{ \"email\" : \"xxxxxx@yahoo.se\", \"password\" : \"xxxxx\" }"
HTTP/1.1 201
Cache-Control: no-store
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MzQwNTE5MjYsInN1YiI6Im1pdHRpcHJvdmVuY2VAeWFob28uc2UifQ.LOJvr5jWouWsLN_Pinlr_F5dntON45hwpUFVmXD2Xqo
Location: http://localhost:8080/api/users/1
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sun, 05 Aug 2018 05:32:07 GMT
{"firstname":"Stephane","lastname":"Eybert","email":"xxxxx@yahoo.se","confirmedEmail":false,"password":"bWl0dGlwcm92ZW5jZUB5YWhvby5zZTptaWduZXQxYjE4ZDQ5MS00ZGRhLTQxZWYtYWM5ZS04N2Y5ODk=","workPhone":null,"userRoles":[{"role":"ROLE_ADMIN","id":1}],"_links":{"self":{"href":"http://localhost:8080/api/users/1"},"roles":{"href":"http://localhost:8080/api/users/1/roles"}},"id":1}[stephane@stephane-ThinkPad-X201 user-rest (master)]
我期望登录请求触发AuthenticationFromCredentialsFilter 过滤器是否正确?使用过滤器进行身份验证并使用令牌响应?登录控制器根本没有被调用?
这是另一个密码更改请求示例,应由安全配置中的AuthenticationFromTokenFilter 过滤器捕获,但未被捕获,因此允许继续到控制器并给出具有200 状态的响应:
$ curl -i -H "Accept:application/json" -H "Content-Type: application/json" "http://localhost:8080/api/users/1/password" -X PUT -d "\"xxxxx\""
HTTP/1.1 200
Cache-Control: no-store
Location: http://localhost:8080/api/users/1
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sat, 04 Aug 2018 20:23:17 GMT
{"firstname":"Stephane","lastname":"Eybert","email":"xxxx@yahoo.se","confirmedEmail":false,"password":"bWl0dGlwcm92ZW5jZUB5YWhvby5zZTptaWduZXRhYTA4OTNiZS0yMzZlLTQ3ZjktOTE2Ny0zOTU0NTY=","workPhone":null,"userRoles":[{"role":"ROLE_ADMIN","id":1}],"_links":{"self":{"href":"http://localhost:8080/api/users/1"},"roles":{"href":"http://localhost:8080/api/users/1/roles"}},"id":1}
对于登录请求使用CustomAuthenticationProvider implements AuthenticationProvider 而不是AuthenticationFromCredentialsFilter 过滤器怎么样?在Spring Boot 2.0.3 下还有可能吗?
我在想这样的事情:
@Autowired
private CustomAuthenticationProvider customAuthenticationProvider;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthenticationProvider);
}
身份验证提供者为:
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
@Autowired
CredentialsService credentialsService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
return credentialsService.authenticate(authentication);
}
@Override
public boolean supports(Class<?> authentication) {
boolean value = (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
return value;
}
}
更新:我也试过这个配置,但它没有改变任何问题:
public AuthenticationFromCredentialsFilter authenticationFromCredentialsFilter() throws Exception {
AuthenticationFromCredentialsFilter authenticationFromCredentialsFilter = new AuthenticationFromCredentialsFilter();
authenticationFromCredentialsFilter.setAuthenticationManager(authenticationManagerBean());
authenticationFromCredentialsFilter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/api/users/login"));
return authenticationFromCredentialsFilter;
}
public AuthenticationFromTokenFilter authenticationFromTokenFilter() throws Exception {
AuthenticationFromTokenFilter authenticationFromTokenFilter = new AuthenticationFromTokenFilter();
authenticationFromTokenFilter.setAuthenticationManager(authenticationManagerBean());
authenticationFromTokenFilter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/**"));
return authenticationFromTokenFilter;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.headers().cacheControl().disable().frameOptions().disable();
http.httpBasic().authenticationEntryPoint(restAuthenticationEntryPoint);
http.addFilterBefore(simpleCORSFilter, UsernamePasswordAuthenticationFilter.class);
http.antMatcher("/api/**")
.addFilterBefore(authenticationFromCredentialsFilter(), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(authenticationFromTokenFilter(), UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/error").permitAll()
.antMatchers("/api/users/login").permitAll()
.antMatchers("/admin/**").hasRole(UserDomainConstants.ROLE_ADMIN)
.anyRequest().authenticated();
}
【问题讨论】:
标签: spring-boot spring-security