国产成人精品久久免费动漫-国产成人精品天堂-国产成人精品区在线观看-国产成人精品日本-a级毛片无码免费真人-a级毛片毛片免费观看久潮喷

您的位置:首頁技術文章
文章詳情頁

SpringSecurity整合springBoot、redis實現登錄互踢功能

瀏覽:92日期:2023-03-11 17:00:00
背景

基于我的文章——《SpringSecurity整合springBoot、redis token動態url權限校驗》。要實現的功能是要實現一個用戶不可以同時在兩臺設備上登錄,有兩種思路:(1)后來的登錄自動踢掉前面的登錄。(2)如果用戶已經登錄,則不允許后來者登錄。需要特別說明的是,項目的基礎是已經是redis維護的session。

配置redisHttpSession

設置spring session由redis 管理。2.1去掉yml中的http session 配置,yml和注解兩者只選其一(同時配置,只有注解配置生效)。至于為什么不用yml,待會提到。

SpringSecurity整合springBoot、redis實現登錄互踢功能

2.2 webSecurityConfig中加入注解@EnableRedisHttpSession

SpringSecurity整合springBoot、redis實現登錄互踢功能

@EnableRedisHttpSession(redisNamespace = 'spring:session:myframe', maxInactiveIntervalInSeconds = 1700, flushMode = FlushMode.ON_SAVE)

登錄后發現redis session namespace已經是我們命名的了

SpringSecurity整合springBoot、redis實現登錄互踢功能

獲取redis管理的sessionRepository

我們要限制一個用戶的登錄,自然要獲取他在系統中的所有session。

2.再去查看springsSession官網的文檔。springsession官網 提供文檔https://docs.spring.io/spring-session/docs/ 2.2.2.RELEASE/reference/html5/#api-findbyindexnamesessionrepository

SessionRepository實現也可以選擇實現FindByIndexNameSessionRepository

FindByIndexNameSessionRepository提供一種方法,用于查找具有給定索引名稱和索引值的所有會話

FindByIndexNameSessionRepository實現時,可以使用方便的方法查找特定用戶的所有會話

/** * redis獲取sessionRepository * RedisIndexedSessionRepository實現 FindByIndexNameSessionRepository接口 */ @Autowired //不加@Lazy這個會報什么循環引用... // Circular reference involving containing bean ’.RedisHttpSessionConfiguration’ @Lazy private FindByIndexNameSessionRepository<? extends Session> sessionRepository;

這里注意一點,當我通過yml配置redis session是,sessionRepository下面會有紅線。

SpringSecurity整合springBoot、redis實現登錄互踢功能

雖然不影響運行,但是強迫癥,所以改用@EnableWebSecurity注解(至于為什么?我也不想知道…)。

將sessionRepository注入SpringSessionBackedSessionRegistry

是spring session為Spring Security提供的什么會話并發的會話注冊表實現,大概是讓springSecurity幫我們去限制登錄,光一個sessionRepository是不行的,還得自己加點工具什么的。webSecurityConfig加入:

/** * 是spring session為Spring Security提供的, * 用于在集群環境下控制會話并發的會話注冊表實現 * @return */ @Bean public SpringSessionBackedSessionRegistry sessionRegistry(){return new SpringSessionBackedSessionRegistry<>(sessionRepository); }

注:https://blog.csdn.net/qq_34136709/article/details/106012825 這篇文章說還需要加一個HttpSessionEventPublisher來監聽session銷毀云云,大概是因為我用的是redis session吧,不需要這個,要了之后還會報錯,啥錯?我忘了。

新增一個session過期后的處理類

先創建一個CustomSessionInformationExpiredStrategy.java來處理session過期后如何通知前端的處理類,內容如下:

public class CustomSessionInformationExpiredStrategy implements SessionInformationExpiredStrategy { @Override public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException {if (log.isDebugEnabled()) { log.debug('{} {}', event.getSessionInformation(), MessageConstant.SESSION_EVICT);}HttpServletResponse response = event.getResponse();response.setContentType(MediaType.APPLICATION_JSON_VALUE);response.setCharacterEncoding(StandardCharsets.UTF_8.toString());String responseJson = JackJsonUtil.object2String(ResponseFactory.fail(CodeMsgEnum.SESSION_EVICT, MessageConstant.SESSION_EVICT));response.getWriter().write(responseJson); }}

注:一般都是自己重新寫返回前端的信息,不會直接用框架拋出的錯誤信息

配置到configure(HttpSecurity http)方法上

.csrf().disable()//登錄互踢.sessionManagement()//在這里設置session的認證策略無效//.sessionAuthenticationStrategy(new ConcurrentSessionControlAuthenticationStrategy(httpSessionConfig.sessionRegistry())).maximumSessions(1).sessionRegistry(sessionRegistry()).maxSessionsPreventsLogin(false) //false表示不阻止登錄,就是新的覆蓋舊的//session失效后要做什么(提示前端什么內容).expiredSessionStrategy(new CustomSessionInformationExpiredStrategy());

注意:https://blog.csdn.net/qq_34136709/article/details/106012825 這篇文章說session認證的原理,我看到它是執行了一個session的認證策略,但是我debug對應的代碼時,發現

SpringSecurity整合springBoot、redis實現登錄互踢功能

這個session認證策略是NullAuthenticatedSessionStrategy,而不是它說的ConcurrentSessionControlAuthenticationStrategy。就是說我需要在哪里去配置這個session 認證策略。第一時間想到了configure(HttpSecurity http)里面配置

SpringSecurity整合springBoot、redis實現登錄互踢功能

結果無效。之后看到別人的代碼,想到這個策略應該是要在登錄的時候加上去,而我們的登錄一般都需要自己重寫,自然上面的寫法會無效。于是我找到了自定義的登錄過濾器。

SpringSecurity整合springBoot、redis實現登錄互踢功能SpringSecurity整合springBoot、redis實現登錄互踢功能

然后發現this.setSessionAuthenticationStrategy(sessionStrategy);確實存在。

public LoginFilter(UserVerifyAuthenticationProvider authenticationManager, CustomAuthenticationSuccessHandler successHandler, CustomAuthenticationFailureHandler failureHandler, SpringSessionBackedSessionRegistry springSessionBackedSessionRegistry) {//設置認證管理器(對登錄請求進行認證和授權)this.authenticationManager = authenticationManager;//設置認證成功后的處理類this.setAuthenticationSuccessHandler(successHandler);//設置認證失敗后的處理類this.setAuthenticationFailureHandler(failureHandler);//配置session認證策略(將springSecurity包裝redis Session作為參數傳入)ConcurrentSessionControlAuthenticationStrategy sessionStrategy = newConcurrentSessionControlAuthenticationStrategy(springSessionBackedSessionRegistry);//最多允許一個sessionsessionStrategy.setMaximumSessions(1);this.setSessionAuthenticationStrategy(sessionStrategy);//可以自定義登錄請求的urlsuper.setFilterProcessesUrl('/myLogin'); }

啟動 后就發現session認證策略已經改為我們設定的策略了。

完整的webSecurityConfig如下:

@Configuration@EnableWebSecurity//RedisFlushMode有兩個參數:ON_SAVE(表示在response commit前刷新緩存),IMMEDIATE(表示只要有更新,就刷新緩存)//yml和注解兩者只選其一(同時配置,只有注解配置生效)@EnableRedisHttpSession(redisNamespace = 'spring:session:myframe', maxInactiveIntervalInSeconds = 5000, flushMode = FlushMode.ON_SAVE)public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserVerifyAuthenticationProvider authenticationManager;//認證用戶類 @Autowired private CustomAuthenticationSuccessHandler successHandler;//登錄認證成功處理類 @Autowired private CustomAuthenticationFailureHandler failureHandler;//登錄認證失敗處理類 @Autowired private MyFilterInvocationSecurityMetadataSource securityMetadataSource;//返回當前URL允許訪問的角色列表 @Autowired private MyAccessDecisionManager accessDecisionManager;//除登錄登出外所有接口的權限校驗 /** * redis獲取sessionRepository * RedisIndexedSessionRepository實現 FindByIndexNameSessionRepository接口 */ @Autowired //不加@Lazy這個會報什么循環引用... // Circular reference involving containing bean ’.RedisHttpSessionConfiguration’ @Lazy private FindByIndexNameSessionRepository<? extends Session> sessionRepository; /** * 是spring session為Spring Security提供的, * 用于在集群環境下控制會話并發的會話注冊表實現 * @return */ @Bean public SpringSessionBackedSessionRegistry sessionRegistry(){return new SpringSessionBackedSessionRegistry<>(sessionRepository); } /** * 密碼加密 * @return */ @Bean @ConditionalOnMissingBean(PasswordEncoder.class) public PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder(); } /** * 配置 HttpSessionIdResolver Bean * 登錄之后將會在 Response Header x-auth-token 中 返回當前 sessionToken * 將token存儲在前端 每次調用的時候 Request Header x-auth-token 帶上 sessionToken */ @Bean public HttpSessionIdResolver httpSessionIdResolver() {return HeaderHttpSessionIdResolver.xAuthToken(); } /** * Swagger等靜態資源不進行攔截 */ @Override public void configure(WebSecurity web) {web.ignoring().antMatchers('/*.html','/favicon.ico','/**/*.html','/**/*.css','/**/*.js','/error','/webjars/**','/resources/**','/swagger-ui.html','/swagger-resources/**','/v2/api-docs'); } @Override protected void configure(HttpSecurity http) throws Exception {http.authorizeRequests()//配置一些不需要登錄就可以訪問的接口,這里配置失效了,放到了securityMetadataSource里面//.antMatchers('/demo/**', '/about/**').permitAll()//任何尚未匹配的URL只需要用戶進行身份驗證.anyRequest().authenticated()//登錄后的接口權限校驗.withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() { @Override public <O extends FilterSecurityInterceptor> O postProcess(O object) {object.setAccessDecisionManager(accessDecisionManager);object.setSecurityMetadataSource(securityMetadataSource);return object; }}).and()//配置登出處理.logout().logoutUrl('/logout').logoutSuccessHandler(new CustomLogoutSuccessHandler()).clearAuthentication(true).and()//用來解決匿名用戶訪問無權限資源時的異常.exceptionHandling().authenticationEntryPoint(new CustomAuthenticationEntryPoint())//用來解決登陸認證過的用戶訪問無權限資源時的異常.accessDeniedHandler(new CustomAccessDeniedHandler()).and()//配置登錄過濾器.addFilter(new LoginFilter(authenticationManager, successHandler, failureHandler, sessionRegistry())).csrf().disable()//登錄互踢.sessionManagement()//在這里設置session的認證策略無效//.sessionAuthenticationStrategy(new ConcurrentSessionControlAuthenticationStrategy(httpSessionConfig.sessionRegistry())).maximumSessions(1).sessionRegistry(sessionRegistry()).maxSessionsPreventsLogin(false) //false表示不阻止登錄,就是新的覆蓋舊的//session失效后要做什么(提示前端什么內容).expiredSessionStrategy(new CustomSessionInformationExpiredStrategy());//配置頭部http.headers().contentTypeOptions().and().xssProtection().and()//禁用緩存.cacheControl().and().httpStrictTransportSecurity().and()//禁用頁面鑲嵌frame劫持安全協議 // 防止iframe 造成跨域.frameOptions().disable(); }}

其他

@Lazyprivate FindByIndexNameSessionRepository<? extends Session> sessionRepository;

至于這個不加@lazy會什么循環引用的問題,我就真的不想理會了??戳撕瞄L時間,都不知道誰和誰發生了循環引用。。。。。

到此這篇關于SpringSecurity整合springBoot、redis——實現登錄互踢的文章就介紹到這了,更多相關SpringSecurity登錄互踢內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!

標簽: Spring
相關文章:
主站蜘蛛池模板: 一级一级 a爱片免费视频 | 奇米色88欧美一区二区 | 国产午夜精品久久久久九九 | 中文字幕 亚洲精品 | 国产性做久久久久久 | 一级特黄aaa大片在 一级特黄aaa大片在线观看 | 久久精品网站免费观看调教 | 国产成人午夜性视频影院 | 久久精品国产午夜伦班片 | 成人欧美视频在线看免费 | 波多野结衣在线免费视频 | 亚洲综合伦理一区 | 涩涩国产精品福利在线观看 | 免费成人 | 国产福利最新手机在线观看 | 中文字幕s级优女区 | 色资源二区在线视频 | 国产日韩欧美一区 | 国产极品精频在线观看 | 中文字幕亚洲不卡在线亚瑟 | 精品一区二区三区在线播放 | 99精品一区二区免费视频 | 一本久久精品一区二区 | 欧美日本道免费一区二区三区 | 免费看一区二区三区 | 欧美日本一区二区三区道 | 欧美色网在线 | 精品国产自 | 欧美一级色视频 | 亚洲精品美女视频 | 亚洲成a人片在线观看中文 亚洲成a人片在线观看中文!!! | 亚洲欧美日韩精品久久亚洲区色播 | 日韩欧美一区二区三区免费观看 | 精品国产精品 | 亚洲免费国产 | 在线视频区 | 欧美成人h精品网站 | 国产精品伦理久久久久 | 成人久久18免费网 | 久久综合免费视频 | 97久久草草超级碰碰碰 |