開發與維運

Spring Security 自定義認證

角色說明

  • 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相關部分

Leave a Reply

Your email address will not be published. Required fields are marked *