Spring Security + JJWT 實現 JWT 認證和授權

關於 JJWT 的使用,可以參考之前的文章:JJWT 使用示例

一、鑑權過濾器

@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
                                    FilterChain filterChain) throws ServletException, IOException {
        String token = httpServletRequest.getHeader(HttpHeaders.AUTHORIZATION);
        if(!StringUtils.isEmpty(token)) {
            UserInfoModel userInfo = JwtUtil.verifyToken(token, JwtConstant.AIM_ACCESS);
            if(userInfo != null) {
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userInfo, null, userInfo.getAuthorities());
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
        }

        filterChain.doFilter(httpServletRequest, httpServletResponse);
    }
}

二、Spring Security 配置

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
    @Autowired
    private EntryPointUnauthorizedHandler entryPointUnauthorizedHandler;
    @Autowired
    private RestAccessDeniedHandler restAccessDeniedHandler;

    @Bean
    GrantedAuthorityDefaults grantedAuthorityDefaults() {
        // 去除 ROLE_ 前綴
        return new GrantedAuthorityDefaults("");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/login").permitAll()
                .anyRequest().authenticated()
                .and().cors()
                .and().csrf().disable();
        http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
        http.exceptionHandling()
                .authenticationEntryPoint(entryPointUnauthorizedHandler)
                .accessDeniedHandler(restAccessDeniedHandler);
        // 不創建會話
        http.sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }
}

其中 EntryPointUnauthorizedHandler 和 RestAccessDeniedHandler 是未認證或未授權異常處理,詳細代碼可以看源碼

三、獲取當前登錄用戶

public class CurrentUserUtil {

    public static UserInfoModel getUserInfo() {

        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if(authentication != null) {
            if(authentication instanceof UsernamePasswordAuthenticationToken) {
                return (UserInfoModel)authentication.getPrincipal();
            }
        }

        return null;
    }
}

測試代碼見 TestController,測試時在請求 Header 中添加 Authorization 即可

完整代碼:GitHub

參考:

  1. Spring Security和JWT實現登錄授權認證
  2. How do I remove the ROLE_ prefix from Spring Security with JavaConfig?
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章