網站首頁 編程語言 正文
根據上篇的實現思想,現在我們正式實現下內容。
需要實現的內容(基于之前的實現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
相關推薦
- 2022-12-22 C++?boost?thread庫用法詳細講解_C 語言
- 2022-11-20 C#?崩潰異常中研究頁堆布局的詳細過程_C#教程
- 2022-12-21 淺析Go語言的數據類型及數組_Golang
- 2022-05-26 Flutter自定義彈窗Dialog效果_Android
- 2022-12-22 Go語言編程通過dwarf獲取內聯函數_Golang
- 2022-10-09 淺談重繪和回流的解析_基礎教程
- 2022-11-09 CSS元素定位
- 2022-02-22 Uncaught TypeError: Cannot read properties of unde
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支