角色说明
- CustomAuthenticationFilter:构建Token类并交给AuthenticationProvider进行验证,继承自AbstractAuthenticationProcessingFilter,AbstractAuthenticationProcessingFilter为UsernamePasswordAuthenticationFilter的父类,封装了登陆过程用到的常用内容及方法.也可以不继承此类完核心功能即可.
- CustomAuthenticationProvider:对支持的token进行校验与shiro中Realm类似,区别是Security将授权与认证合并了.
- CustomAuthenticationToken:自定义token,存储自定义内容,程序中使用SecurityContextHolder.getContext().getAuthentication()来获取
java配置
过滤器配置
public class CustomAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
public CustomAuthenticationFilter() {
super(new AntPathRequestMatcher("/custom/**"));
//
setContinueChainBeforeSuccessfulAuthentication(true);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
CustomAuthenticationToken authentication = null;
try {
Enumeration<String> headers = request.getHeaders("secretKey");
String secretKey = headers.nextElement();
// 通过request中参数构建自定义token,与CustomAuthenticationProvider对应即可
authentication = new CustomAuthenticationToken(secretKey, secretKey);
//设置附属信息,sessionid,ip
setDetails(request, authentication);
//通过Provider验证token
authentication = (CustomAuthenticationToken) getAuthenticationManager().authenticate(authentication);
//
SecurityContextHolder.getContext().setAuthentication(authentication);
} catch (Exception e) {
throw new AuthenticationServiceException("secretKey认证失败",e);
}
return authentication;
}
protected void setDetails(HttpServletRequest request,
CustomAuthenticationToken authRequest) {
authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
}
}
说明
- 此示例是在请求头中增加参数用于认证,并没有后续的登陆成功处理所以设置了setContinueChainBeforeSuccessfulAuthentication
- setContinueChainBeforeSuccessfulAuthentication设置为true表示认证成功之后进入后续过滤,不走后续的登陆成功处理
- 需要手动将认证结果存入SecurityContextHolder中避免后续拿不到认证信息.
Provider 配置
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String secretKey = (String) authentication.getCredentials();
//自定义校验逻辑
if(!"123".equals(secretKey)){
throw new InsufficientAuthenticationException("认证错误");
}
Set<String> dbAuthsSet = new HashSet<String>();
dbAuthsSet.add("customUser");
Collection<? extends GrantedAuthority> authorities = AuthorityUtils.createAuthorityList(dbAuthsSet.toArray(new String[0]));
return new CustomAuthenticationToken(secretKey, secretKey, authorities);
}
@Override
public boolean supports(Class<?> authentication) {
return CustomAuthenticationToken.class.isAssignableFrom(authentication);
}
}
SecurityConfig配置
@Order(2)
@Configuration
public class CustomSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomAuthenticationProvider customAuthenticationProvider;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.antMatcher("/custom/**")
.addFilterBefore(customAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER)
.and().authorizeRequests().antMatchers("/custom/**").authenticated();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthenticationProvider);
}
@Bean
public CustomAuthenticationFilter customAuthenticationFilter() throws Exception {
CustomAuthenticationFilter filter = new CustomAuthenticationFilter();
filter.setAuthenticationManager(super.authenticationManagerBean());
return filter;
}
}
相关代码
https://gitee.com/MeiJM/spring-cram/tree/master/customSecurity中CustomSecurityConfig相关部分