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

學(xué)無先后,達(dá)者為師

網(wǎng)站首頁(yè) 編程語(yǔ)言 正文

SpringSecurity 自定義JwtAuthorFilter基于JWT的Token驗(yàn)證

作者:Survivor001 更新時(shí)間: 2022-02-26 編程語(yǔ)言

根據(jù)上篇的實(shí)現(xiàn)思想,現(xiàn)在我們正式實(shí)現(xiàn)下內(nèi)容。

需要實(shí)現(xiàn)的內(nèi)容(基于之前的實(shí)現(xiàn)SpringSecurity 架子):

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

? ? ? 因?yàn)轵?yàn)證環(huán)節(jié)需要實(shí)現(xiàn)從redis獲取上下文,設(shè)置為SecurityContextHolder。

2. 自定義實(shí)現(xiàn)JwtAuthorFilter,攔截所有請(qǐng)求,對(duì)token進(jìn)行驗(yàn)證,驗(yàn)證內(nèi)容:是否攜帶token,是? ? ? 否有效等(根據(jù)需求實(shí)現(xiàn)):進(jìn)行token驗(yàn)證,無效token或者無token將直接進(jìn)入后續(xù)過濾器? ? ? ? ? 中,但是將無法獲取SecurityContextHolder上下文內(nèi)容,在關(guān)閉session管理的情況下,授權(quán)認(rèn)? ? ? 證失敗。

3.?JwtAuthorFilter加入過濾鏈。

實(shí)現(xiàn):

1. 修改?JwtAuthenticationSuccessHandler

/**
 * @Author: 一只會(huì)飛的豬
 * @Date: 2021/9/11 18:50
 * @Version 1.0
 * springsecurity 自定義認(rèn)證成功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();
                // 將當(dāng)前用戶信息存入redis,key為 REDIS_KEY + userid  記錄用戶登錄情況,以及后續(xù)驗(yàn)證失效時(shí)間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. 自定義實(shí)現(xiàn)JwtAuthorFilter

/**
 * @Author: 一只會(huì)飛的豬
 * @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 {
            // 獲取請(qǐng)求頭傳遞過來的token數(shù)據(jù)
            String token = TokenUtils.getToken( httpServletRequest );
            if (token != null && !"".equals( token )) {
                // 驗(yàn)證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為空直接下一步過濾器,此時(shí)上線文中無用戶信息,所有在后續(xù)認(rèn)證環(huán)節(jié)失敗
        filterChain.doFilter( httpServletRequest, httpServletResponse );
    }
}

3.?JwtAuthorFilter加入過濾鏈

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

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

結(jié)果截圖:

不適用token,或者失效:

正常使用token:

?

?springsecurity 提供的了完善的過濾鏈來處理認(rèn)證和授權(quán),保障服務(wù)安全。針對(duì)不同企業(yè)不同需要,其同樣也有高擴(kuò)展性,完全可以根據(jù)各自企業(yè)的需求實(shí)現(xiàn)需要的拓展內(nèi)容。 比如基于OAuth2的SSO單點(diǎn)登錄的實(shí)現(xiàn)等等。

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

欄目分類
最近更新