日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

SpringSecurity 自定義JwtAuthorFilter基于JWT的Token驗證

作者:Survivor001 更新時間: 2022-02-26 編程語言

根據上篇的實現思想,現在我們正式實現下內容。

需要實現的內容(基于之前的實現SpringSecurity 架子):

1.? 修改 JwtAuthenticationSuccessHandler ,需要將上下文信息存入redis:

? ? ? 因為驗證環節需要實現從redis獲取上下文,設置為SecurityContextHolder。

2. 自定義實現JwtAuthorFilter,攔截所有請求,對token進行驗證,驗證內容:是否攜帶token,是? ? ? 否有效等(根據需求實現):進行token驗證,無效token或者無token將直接進入后續過濾器? ? ? ? ? 中,但是將無法獲取SecurityContextHolder上下文內容,在關閉session管理的情況下,授權認? ? ? 證失敗。

3.?JwtAuthorFilter加入過濾鏈。

實現:

1. 修改?JwtAuthenticationSuccessHandler

/**
 * @Author: 一只會飛的豬
 * @Date: 2021/9/11 18:50
 * @Version 1.0
 * springsecurity 自定義認證成功handler
 **/
@Component
public class JwtAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
    private static final String REDIS_KEY = "USER_LOGIN:";
    @Autowired
    RedisCache redisCache;
    @Override
    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
            try {
                Map<String,Object> map = new HashMap <>(  );
                httpServletResponse.setContentType("application/json;charset=utf-8");
                LoginUser user = (LoginUser) authentication.getPrincipal();
                SysUser sysUser = user.getUserInfo();
                // 將當前用戶信息存入redis,key為 REDIS_KEY + userid  記錄用戶登錄情況,以及后續驗證失效時間5分鐘
                redisCache.setCacheObject( REDIS_KEY+sysUser.getId(),user,300, TimeUnit.SECONDS);
                String token = JwtTokenUtils.createToken( String.valueOf( sysUser.getId() ), false );
                map.put( "token",token );
                map.put( "userinfo",sysUser );
                map.put( "code",200 );
                httpServletResponse.getWriter().write(JSONObject.toJSONString(map));

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
}

2. 自定義實現JwtAuthorFilter

/**
 * @Author: 一只會飛的豬
 * @Date: 2021/9/14 10:07
 * @Version 1.0
 **/
@Component
public class JwtAuthorFilter extends OncePerRequestFilter {
    private static final String REDIS_KEY = "USER_LOGIN:";
    @Autowired
    RedisCache redisCache;

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        try {
            // 獲取請求頭傳遞過來的token數據
            String token = TokenUtils.getToken( httpServletRequest );
            if (token != null && !"".equals( token )) {
                // 驗證token是否有效
                boolean expiration = JwtTokenUtils.isExpiration( token );
                if(expiration){
                    // 過期了,攔截訪問
                    filterChain.doFilter( httpServletRequest, httpServletResponse );
                    return;
                }
                String userId = JwtTokenUtils.getUserID( token );
                // 通過userID獲取redis中的緩存信息
                LoginUser loginUser  = redisCache.getCacheObject( REDIS_KEY + userId );
                if (loginUser != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                    //  刷新令牌
                    redisCache.setCacheObject(REDIS_KEY + userId, loginUser, 300, TimeUnit.SECONDS);

                    //  將從redis獲取到的用戶信息set到上下文中
                    LoginJwtToken loginJwtToken = new LoginJwtToken( loginUser.getAuthorities(), loginUser, loginUser.getPassword() );
                    loginJwtToken.setDetails( new WebAuthenticationDetailsSource().buildDetails( httpServletRequest ) );
                    SecurityContextHolder.getContext().setAuthentication( loginJwtToken );
                }
            }
        }catch (MalformedJwtException e){
            filterChain.doFilter( httpServletRequest, httpServletResponse );
            return;
        }
        // 如果token為空直接下一步過濾器,此時上線文中無用戶信息,所有在后續認證環節失敗
        filterChain.doFilter( httpServletRequest, httpServletResponse );
    }
}

3.?JwtAuthorFilter加入過濾鏈

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable();
        // 關閉security session管理,意味著用戶認證之后信息不會存儲到session中,下面自定義了token過濾器處理,使用redis實現緩存
        http.sessionManagement().sessionCreationPolicy( SessionCreationPolicy.STATELESS );
        http.authorizeRequests().antMatchers( "/**/test" ).permitAll();
        http.authorizeRequests().antMatchers( "/**/login" ).permitAll()
                 .antMatchers( "/system/user/list" ).authenticated();

        // 設置用于認證的管理器
        jwtLoginFilter.setAuthenticationManager( this.authenticationManagerBean() );
        // 自定義的認證過濾器加入filter鏈
        http.addFilterAt( jwtLoginFilter,UsernamePasswordAuthenticationFilter.class );
        // 自定義認證成功Handler加入過濾器
        jwtLoginFilter.setAuthenticationSuccessHandler( jwtAuthenticationSuccessHandler );
        // 自定義認證失敗Handler加入過濾器
        jwtLoginFilter.setAuthenticationFailureHandler( jwtAuthenticationFailureHandler );
        // 自定義的Provider 加入認證管理器
        http.authenticationProvider( jwtAuthProvider );
        // 自定義驗證失敗點
        http.exceptionHandling().authenticationEntryPoint( myAuthenticationEntryPoint );
        // 加入token驗證過濾器
        http.addFilterBefore( jwtAuthorFilter,JwtLoginFilter.class );
    }

結果截圖:

不適用token,或者失效:

正常使用token:

?

?springsecurity 提供的了完善的過濾鏈來處理認證和授權,保障服務安全。針對不同企業不同需要,其同樣也有高擴展性,完全可以根據各自企業的需求實現需要的拓展內容。 比如基于OAuth2的SSO單點登錄的實現等等。

原文鏈接:https://blog.csdn.net/qq_31142237/article/details/120311067

欄目分類
最近更新