电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

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

Spring Security 實現“記住我”功能及原理解析

瀏覽:62日期:2023-09-05 08:05:36

這章繼續擴展功能,來一個“記住我”的功能實現,就是說用戶在登錄一次以后,系統會記住這個用戶一段時間,這段時間內用戶不需要重新登錄就可以使用系統。

記住我功能基本原理

原理說明

用戶登錄發送認證請求的時候會被UsernamePasswordAuthenticationFilter認證攔截,認證成功以后會調用一個RememberMeService服務,服務里面有一個TokenRepository,這個服務會生成一個Token,然后將Token寫入到瀏覽器的Cookie同時會使用TokenRepository把生成的Token寫到數據庫里面,因為這個動作是在認證成功以后做的,所以在Token寫入數據庫的時候會把用戶名同時寫入數據庫。 假如瀏覽器關了重新訪問系統,用戶不需要再次登錄就可以訪問,這個時候請求在過濾器鏈上會經過RememberMeAuthenticationFilter,這個過濾器的作用是讀取Cookie中的Token交給RemeberMeService,RemeberMeService會用TokenRepository到數據庫里去查這個Token在數據庫里有沒有記錄,如果有記錄就會把用戶名取出來,取出來以后會進行各種校驗然后生成新Token再調用之前的UserDetailService,去獲取用戶的信息,然后把用戶信息放到SecurityContext里面,到這里就把用戶給登錄上了。

圖解說明

Spring Security 實現“記住我”功能及原理解析

RememberMeAuthenticationFilter位于過濾器鏈的哪一環?

圖解

Spring Security 實現“記住我”功能及原理解析

首先其他認證過濾器會先進行認證,當其他過濾器都無法認證時,RememberMeAuthenticationFilter會嘗試去做認證。

記住我功能具體實現

前端頁面

登錄的時候加上一行記住我的勾選按鈕,這里要注意,name一定要是remember-me,下面源碼部分會提到。

<tr><td colspan=’2’><input name='remember-me' type='checkbox' value='true' />記住我</td></tr>

后臺

首先配置TokenRepositoryBean

/** * 記住我功能的Token存取器配置 * * @return */@Beanpublic PersistentTokenRepository persistentTokenRepository() {JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();tokenRepository.setDataSource(dataSource);// 啟動的時候自動創建表,建表語句 JdbcTokenRepositoryImpl 已經都寫好了tokenRepository.setCreateTableOnStartup(true);return tokenRepository;}

然后需要在 configure 配置方法那邊進行記住我功能所有組件的配置

protected void configure(HttpSecurity http) throws Exception {ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter();http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class).formLogin().loginPage('/authentication/require').loginProcessingUrl('/authentication/form').successHandler(meicloudAuthenticationSuccessHandler).failureHandler(meicloudAuthenticationFailureHandler)// 配置記住我功能.and().rememberMe()// 配置TokenRepository.tokenRepository(persistentTokenRepository())// 配置Token過期時間.tokenValiditySeconds(3600)// 最終拿到用戶名之后,使用UserDetailsService去做登錄.userDetailsService(userDetailsService).and().authorizeRequests().antMatchers('/authentication/require', securityProperties.getBrowser().getSignInPage(), '/code/image').permitAll().anyRequest().authenticated().and().csrf().disable();}

記住我功能Spring Security源碼解析

登錄之前“記住我”源碼流程

在認證成功之后,會調用successfulAuthentication方法(這些第五章源碼部分已經學習過),在將認證信息保存到Context后,RememberMeServices就會調用它的loginSuccess方法。

protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException { if (this.logger.isDebugEnabled()) { this.logger.debug('Authentication success. Updating SecurityContextHolder to contain: ' + authResult); } SecurityContextHolder.getContext().setAuthentication(authResult); this.rememberMeServices.loginSuccess(request, response, authResult); if (this.eventPublisher != null) { this.eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass())); } this.successHandler.onAuthenticationSuccess(request, response, authResult); }

loginSuccess方法里面會先檢查請求中是否有name為remember-me的參數,有才進行下一步。

public final void loginSuccess(HttpServletRequest request, HttpServletResponse response, Authentication successfulAuthentication) { // this.parameter = 'remember-me' if (!this.rememberMeRequested(request, this.parameter)) { this.logger.debug('Remember-me login not requested.'); } else { this.onLoginSuccess(request, response, successfulAuthentication); } }

再進入onLoginSuccess方法,里面主要就是進行寫庫和寫Cookie的操作。

protected void onLoginSuccess(HttpServletRequest request, HttpServletResponse response, Authentication successfulAuthentication) { String username = successfulAuthentication.getName(); this.logger.debug('Creating new persistent login for user ' + username); // 生成Token PersistentRememberMeToken persistentToken = new PersistentRememberMeToken(username, this.generateSeriesData(), this.generateTokenData(), new Date()); try { // 將Token和userName插入數據庫 this.tokenRepository.createNewToken(persistentToken); // 將Token寫到Cookie中 this.addCookie(persistentToken, request, response); } catch (Exception var7) { this.logger.error('Failed to save persistent token ', var7); } }

登錄之后“記住我”源碼流程

首先會進入RememberMeAuthenticationFilter,會先判斷前面的過濾器是否進行過認證(Context中是否有認證信息),未進行過認證的話會調用RememberMeServices的autoLogin方法。

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest)req; HttpServletResponse response = (HttpServletResponse)res; if (SecurityContextHolder.getContext().getAuthentication() == null) { Authentication rememberMeAuth = this.rememberMeServices.autoLogin(request, response); if (rememberMeAuth != null) { try { rememberMeAuth = this.authenticationManager.authenticate(rememberMeAuth); SecurityContextHolder.getContext().setAuthentication(rememberMeAuth); this.onSuccessfulAuthentication(request, response, rememberMeAuth); if (this.logger.isDebugEnabled()) { this.logger.debug('SecurityContextHolder populated with remember-me token: ’' + SecurityContextHolder.getContext().getAuthentication() + '’'); } if (this.eventPublisher != null) { this.eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(SecurityContextHolder.getContext().getAuthentication(), this.getClass())); } if (this.successHandler != null) { this.successHandler.onAuthenticationSuccess(request, response, rememberMeAuth); return; } } catch (AuthenticationException var8) { if (this.logger.isDebugEnabled()) { this.logger.debug('SecurityContextHolder not populated with remember-me token, as AuthenticationManager rejected Authentication returned by RememberMeServices: ’' + rememberMeAuth + '’; invalidating remember-me token', var8); } this.rememberMeServices.loginFail(request, response); this.onUnsuccessfulAuthentication(request, response, var8); } } chain.doFilter(request, response); } else { if (this.logger.isDebugEnabled()) { this.logger.debug('SecurityContextHolder not populated with remember-me token, as it already contained: ’' + SecurityContextHolder.getContext().getAuthentication() + '’'); } chain.doFilter(request, response); } }

autoLogin方法里面,主要調用this.processAutoLoginCookie(cookieTokens, request, response)這個方法獲取數據庫中的用戶信息,其步驟是:

解析前端傳來的Cookie,里面包含了Token和seriesId,它會使用seriesId查找數據庫的Token 檢查Cookie中的Token和數據庫查出來的Token是否一樣 一樣的話再檢查數據庫中的Token是否已過期 如果以上都符合的話,會使用舊的用戶名和series重新new一個Token,這時過期時間也重新刷新 然后將新的Token保存回數據庫,同時添加回Cookie中 最后再調用UserDetailsService的loadUserByUsername方法返回UserDetails

protected UserDetails processAutoLoginCookie(String[] cookieTokens, HttpServletRequest request, HttpServletResponse response) { if (cookieTokens.length != 2) { throw new InvalidCookieException('Cookie token did not contain 2 tokens, but contained ’' + Arrays.asList(cookieTokens) + '’'); } else { String presentedSeries = cookieTokens[0]; String presentedToken = cookieTokens[1]; PersistentRememberMeToken token = this.tokenRepository.getTokenForSeries(presentedSeries); if (token == null) { throw new RememberMeAuthenticationException('No persistent token found for series id: ' + presentedSeries); } else if (!presentedToken.equals(token.getTokenValue())) { this.tokenRepository.removeUserTokens(token.getUsername()); throw new CookieTheftException(this.messages.getMessage('PersistentTokenBasedRememberMeServices.cookieStolen', 'Invalid remember-me token (Series/token) mismatch. Implies previous cookie theft attack.')); } else if (token.getDate().getTime() + (long)this.getTokenValiditySeconds() * 1000L < System.currentTimeMillis()) { throw new RememberMeAuthenticationException('Remember-me login has expired'); } else { if (this.logger.isDebugEnabled()) { this.logger.debug('Refreshing persistent login token for user ’' + token.getUsername() + '’, series ’' + token.getSeries() + '’'); } PersistentRememberMeToken newToken = new PersistentRememberMeToken(token.getUsername(), token.getSeries(), this.generateTokenData(), new Date()); try { this.tokenRepository.updateToken(newToken.getSeries(), newToken.getTokenValue(), newToken.getDate()); this.addCookie(newToken, request, response); } catch (Exception var9) { this.logger.error('Failed to update token: ', var9); throw new RememberMeAuthenticationException('Autologin failed due to data access problem'); } return this.getUserDetailsService().loadUserByUsername(token.getUsername()); } } }

回到RememberMeAuthenticationFilter,在調用了autoLogin方法之后得到了rememberMeAuth,然后再對其進行一個認證,認證成功之后保存到SecurityContext中,至此整個RememberMe自動登錄流程源碼結束。

相關閱讀:

Spring Security實現圖形驗證碼登錄

Spring Security實現短信驗證碼登錄

總結

到此這篇關于Spring Security 實現“記住我”功能及原理解析的文章就介紹到這了,更多相關spring security記住我內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!

標簽: Spring
相關文章:
主站蜘蛛池模板: 膜结构_ETFE膜结构_膜结构厂家_膜结构设计-深圳市烨兴智能空间技术有限公司 | 非标压力容器_碳钢储罐_不锈钢_搪玻璃反应釜厂家-山东首丰智能环保装备有限公司 | 华溶溶出仪-Memmert稳定箱-上海协烁仪器科技有限公司 | 天津力值检测-天津管道检测-天津天诚工程检测技术有限公司 | 学习安徽网| 沥青灌缝机_路面灌缝机_道路灌缝机_沥青灌缝机厂家_济宁萨奥机械有限公司 | 电地暖-电采暖-发热膜-石墨烯电热膜品牌加盟-暖季地暖厂家 | 污泥烘干机-低温干化机-工业污泥烘干设备厂家-焦作市真节能环保设备科技有限公司 | 生产加气砖设备厂家很多,杜甫机械加气砖设备价格公道 | 垃圾处理设备_餐厨垃圾处理设备_厨余垃圾处理设备_果蔬垃圾处理设备-深圳市三盛环保科技有限公司 | 恒温恒湿箱(药品/保健品/食品/半导体/细菌)-兰贝石(北京)科技有限公司 | 济宁工业提升门|济宁电动防火门|济宁快速堆积门-济宁市统一电动门有限公司 | 高效节能电机_伺服主轴电机_铜转子电机_交流感应伺服电机_图片_型号_江苏智马科技有限公司 | 宏源科技-房地产售楼系统|线上开盘系统|售楼管理系统|线上开盘软件 | 升降机-高空作业车租赁-蜘蛛车-曲臂式伸缩臂剪叉式液压升降平台-脚手架-【普雷斯特公司厂家】 | 工业CT-无锡璟能智能仪器有限公司 | 轻型地埋电缆故障测试仪,频响法绕组变形测试仪,静荷式卧式拉力试验机-扬州苏电 | 济南律师,济南法律咨询,山东法律顾问-山东沃德律师事务所 | 点焊机-缝焊机-闪光对焊机-电阻焊设备生产厂家-上海骏腾发智能设备有限公司 | 网优资讯-为循环资源、大宗商品、工业服务提供资讯与行情分析的数据服务平台 | 缠膜机|缠绕包装机|无纺布包装机-济南达伦特机械设备有限公司 | 大巴租车平台承接包车,通勤班车,巴士租赁业务 - 鸿鸣巴士 | 纯水电导率测定仪-万用气体检测仪-低钠测定仪-米沃奇科技(北京)有限公司www.milwaukeeinst.cn 锂辉石检测仪器,水泥成分快速分析仪-湘潭宇科分析仪器有限公司 手术室净化装修-手术室净化工程公司-华锐手术室净化厂家 | 天坛家具官网| 真空冷冻干燥机_国产冻干机_冷冻干燥机_北京四环冻干 | 恒压供水控制柜|无负压|一体化泵站控制柜|PLC远程调试|MCGS触摸屏|自动控制方案-联致自控设备 | 科威信洗净科技,碳氢清洗机,超声波清洗机,真空碳氢清洗机 | 净化板-洁净板-净化板价格-净化板生产厂家-山东鸿星新材料科技股份有限公司 | 玻璃钢罐_玻璃钢储罐_盐酸罐厂家-河北华盛节能设备有限公司 | 「银杏树」银杏树行情价格_银杏树种植_山东程锦园林 | 领先的大模型技术与应用公司-中关村科金| 交流伺服电机|直流伺服|伺服驱动器|伺服电机-深圳市华科星电气有限公司 | 四川成都干燥设备_回转筒干燥机_脉冲除尘器_输送设备_热风炉_成都川工星科机电设备有限公司 | 招商帮-一站式网络营销服务|互联网整合营销|网络推广代运营|信息流推广|招商帮企业招商好帮手|搜索营销推广|短视视频营销推广 | 圆窗水平仪|伊莉莎冈特elesa+ganter| 400电话_400电话申请_866元/年_【400电话官方业务办理】-俏号网 3dmax渲染-效果图渲染-影视动画渲染-北京快渲科技有限公司 | 搅拌磨|搅拌球磨机|循环磨|循环球磨机-无锡市少宏粉体科技有限公司 | 交通信号灯生产厂家_红绿灯厂家_电子警察监控杆_标志杆厂家-沃霖电子科技 | 热熔胶网膜|pes热熔网膜价格|eva热熔胶膜|热熔胶膜|tpu热熔胶膜厂家-苏州惠洋胶粘制品有限公司 | 油罐车_加油机_加油卷盘_加油机卷盘_罐车人孔盖_各类球阀_海底阀等车用配件厂家-湖北华特专用设备有限公司 | 滁州高低温冲击试验箱厂家_安徽高低温试验箱价格|安徽希尔伯特 |