日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

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

Spring Security 實現短信驗證碼登錄功能

瀏覽:130日期:2023-09-05 09:49:10

之前文章都是基于用戶名密碼登錄,第六章圖形驗證碼登錄其實還是用戶名密碼登錄,只不過多了一層圖形驗證碼校驗而已;Spring Security默認提供的認證流程就是用戶名密碼登錄,整個流程都已經固定了,雖然提供了一些接口擴展,但是有些時候我們就需要有自己特殊的身份認證邏輯,比如用短信驗證碼登錄,它和用戶名密碼登錄的邏輯是不一樣的,這時候就需要重新寫一套身份認證邏輯。

開發短信驗證碼接口

獲取驗證碼

短信驗證碼的發送獲取邏輯和圖片驗證碼類似,這里直接貼出代碼。

@GetMapping('/code/sms')public void createSmsCode(HttpServletRequest request, HttpServletResponse response) throws Exception {// 創建驗證碼ValidateCode smsCode = createCodeSmsCode(request);// 將驗證碼放到session中sessionStrategy.setAttribute(new ServletWebRequest(request), SMS_CODE_SESSION_KEY, smsCode);String mobile = ServletRequestUtils.getRequiredStringParameter(request, 'mobile');// 發送驗證碼smsCodeSender.send(mobile, smsCode.getCode());}

前端代碼

<tr><td>手機號:</td><td><input type='text' name='mobile' value='13012345678'></td></tr><tr><td>短信驗證碼:</td><td><input type='text' name='smsCode'><a href='http://m.b3g6.com/code/sms?mobile=13012345678' rel='external nofollow' >發送驗證碼</a></td></tr>

短信驗證碼流程原理

短信驗證碼登錄和用戶名密碼登錄對比

Spring Security 實現短信驗證碼登錄功能

步驟流程

首先點擊登錄應該會被SmsAuthenticationFilter過濾器處理,這個過濾器拿到請求以后會在登錄請求中拿到手機號,然后封裝成自定義的一個SmsAuthenticationToken(未認證)。 這個Token也會傳給AuthenticationManager,因為AuthenticationManager整個系統只有一個,它會檢索系統中所有的AuthenticationProvider,這時候我們要提供自己的SmsAuthenticationProvider,用它來校驗自己寫的SmsAuthenticationToken的手機號信息。 在校驗的過程中同樣會調用UserDetailsService,把手機號傳給它讓它去讀用戶信息,去判斷是否能登錄,登錄成功的話再把SmsAuthenticationToken標記為已認證。 到這里為止就是短信驗證碼的認證流程,上面的流程并沒有提到校驗驗證碼信息,其實它的驗證流程和圖形驗證碼驗證流程也是類似,同樣是在SmsAuthenticationFilter過濾器之前加一個過濾器來驗證短信驗證碼。

代碼實現

SmsCodeAuthenticationToken

作用:封裝認證Token 實現:可以繼承AbstractAuthenticationToken抽象類,該類實現了Authentication接口

public class SmsCodeAuthenticationToken extends AbstractAuthenticationToken {private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;private final Object principal;/** * 進入SmsAuthenticationFilter時,構建一個未認證的Token * * @param mobile */public SmsCodeAuthenticationToken(String mobile) {super(null);this.principal = mobile;setAuthenticated(false);}/** * 認證成功以后構建為已認證的Token * * @param principal * @param authorities */public SmsCodeAuthenticationToken(Object principal,Collection<? extends GrantedAuthority> authorities) {super(authorities);this.principal = principal;super.setAuthenticated(true);}@Overridepublic Object getCredentials() {return null;}@Overridepublic Object getPrincipal() {return this.principal;}@Overridepublic void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {if (isAuthenticated) {throw new IllegalArgumentException('Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead');}super.setAuthenticated(false);}@Overridepublic void eraseCredentials() {super.eraseCredentials();}}

SmsCodeAuthenticationFilter

作用:處理短信登錄的請求,構建Token,把請求信息設置到Token中。 實現:該類可以模仿UsernamePasswordAuthenticationFilter類,繼承AbstractAuthenticationProcessingFilter抽象類

public class SmsCodeAuthenticationFilter extends AbstractAuthenticationProcessingFilter {private String mobileParameter = 'mobile';private boolean postOnly = true; /** * 表示要處理的請求路徑 */public SmsCodeAuthenticationFilter() { super(new AntPathRequestMatcher('/authentication/mobile', 'POST'));} @Overridepublic Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)throws AuthenticationException {if (postOnly && !request.getMethod().equals('POST')) {throw new AuthenticationServiceException('Authentication method not supported: ' + request.getMethod());}String mobile = obtainMobile(request);if (mobile == null) {mobile = '';}mobile = mobile.trim();SmsCodeAuthenticationToken authRequest = new SmsCodeAuthenticationToken(mobile);// 把請求信息設到Token中setDetails(request, authRequest);return this.getAuthenticationManager().authenticate(authRequest);}/** * 獲取手機號 */protected String obtainMobile(HttpServletRequest request) {return request.getParameter(mobileParameter);}protected void setDetails(HttpServletRequest request, SmsCodeAuthenticationToken authRequest) {authRequest.setDetails(authenticationDetailsSource.buildDetails(request));}public void setMobileParameter(String usernameParameter) {Assert.hasText(usernameParameter, 'Username parameter must not be empty or null');this.mobileParameter = usernameParameter;}public void setPostOnly(boolean postOnly) {this.postOnly = postOnly;}public final String getMobileParameter() {return mobileParameter;}}

SmsAuthenticationProvider

作用:提供認證Token的校驗邏輯,配置為能夠支持SmsCodeAuthenticationToken的校驗 實現:實現AuthenticationProvider接口,實現其兩個方法。

public class SmsCodeAuthenticationProvider implements AuthenticationProvider {private UserDetailsService userDetailsService; /** * 進行身份認證的邏輯 * * @param authentication * @return * @throws AuthenticationException */@Overridepublic Authentication authenticate(Authentication authentication) throws AuthenticationException {SmsCodeAuthenticationToken authenticationToken = (SmsCodeAuthenticationToken) authentication;UserDetails user = userDetailsService.loadUserByUsername((String) authenticationToken.getPrincipal());if (user == null) {throw new InternalAuthenticationServiceException('無法獲取用戶信息');}SmsCodeAuthenticationToken authenticationResult = new SmsCodeAuthenticationToken(user, user.getAuthorities());authenticationResult.setDetails(authenticationToken.getDetails());return authenticationResult;} /** * 表示支持校驗的Token,這里是SmsCodeAuthenticationToken * * @param authentication * @return */@Overridepublic boolean supports(Class<?> authentication) {return SmsCodeAuthenticationToken.class.isAssignableFrom(authentication);}public UserDetailsService getUserDetailsService() {return userDetailsService;}public void setUserDetailsService(UserDetailsService userDetailsService) {this.userDetailsService = userDetailsService;}}

ValidateCodeFilter

:校驗短信驗證碼 實現:和圖形驗證碼類似,繼承OncePerRequestFilter接口防止多次調用,主要就是驗證碼驗證邏輯,驗證通過則繼續下一個過濾器。

@Component('validateCodeFilter')public class ValidateCodeFilter extends OncePerRequestFilter implements InitializingBean {/** * 驗證碼校驗失敗處理器 */@Autowiredprivate AuthenticationFailureHandler authenticationFailureHandler;/** * 系統配置信息 */@Autowiredprivate SecurityProperties securityProperties;/** * 系統中的校驗碼處理器 */@Autowiredprivate ValidateCodeProcessorHolder validateCodeProcessorHolder;/** * 存放所有需要校驗驗證碼的url */private Map<String, ValidateCodeType> urlMap = new HashMap<>();/** * 驗證請求url與配置的url是否匹配的工具類 */private AntPathMatcher pathMatcher = new AntPathMatcher();/** * 初始化要攔截的url配置信息 */@Overridepublic void afterPropertiesSet() throws ServletException {super.afterPropertiesSet();urlMap.put('/authentication/mobile', ValidateCodeType.SMS);addUrlToMap(securityProperties.getCode().getSms().getUrl(), ValidateCodeType.SMS);}/** * 講系統中配置的需要校驗驗證碼的URL根據校驗的類型放入map * * @param urlString * @param type */protected void addUrlToMap(String urlString, ValidateCodeType type) {if (StringUtils.isNotBlank(urlString)) {String[] urls = StringUtils.splitByWholeSeparatorPreserveAllTokens(urlString, ',');for (String url : urls) {urlMap.put(url, type);}}}/** * 驗證短信驗證碼 * * @param request * @param response * @param chain * @throws ServletException * @throws IOException */@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)throws ServletException, IOException {ValidateCodeType type = getValidateCodeType(request);if (type != null) {logger.info('校驗請求(' + request.getRequestURI() + ')中的驗證碼,驗證碼類型' + type);try {// 進行驗證碼的校驗validateCodeProcessorHolder.findValidateCodeProcessor(type).validate(new ServletWebRequest(request, response));logger.info('驗證碼校驗通過');} catch (ValidateCodeException exception) {// 如果校驗拋出異常,則交給我們之前文章定義的異常處理器進行處理authenticationFailureHandler.onAuthenticationFailure(request, response, exception);return;}}// 繼續調用后邊的過濾器chain.doFilter(request, response);}/** * 獲取校驗碼的類型,如果當前請求不需要校驗,則返回null * * @param request * @return */private ValidateCodeType getValidateCodeType(HttpServletRequest request) {ValidateCodeType result = null;if (!StringUtils.equalsIgnoreCase(request.getMethod(), 'GET')) {Set<String> urls = urlMap.keySet();for (String url : urls) {if (pathMatcher.match(url, request.getRequestURI())) {result = urlMap.get(url);}}}return result;}}

添加配置

SmsCodeAuthenticationSecurityConfig

作用:配置SmsCodeAuthenticationFilter,后面需要把這些配置加到主配置類BrowserSecurityConfig

@Componentpublic class SmsCodeAuthenticationSecurityConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {@Autowiredprivate AuthenticationSuccessHandler meicloudAuthenticationSuccessHandler;@Autowiredprivate AuthenticationFailureHandler meicloudAuthenticationFailureHandler;@Autowiredprivate UserDetailsService userDetailsService;@Autowiredprivate PersistentTokenRepository persistentTokenRepository;@Overridepublic void configure(HttpSecurity http) throws Exception {SmsCodeAuthenticationFilter smsCodeAuthenticationFilter = new SmsCodeAuthenticationFilter();// 設置AuthenticationManagersmsCodeAuthenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));// 設置登錄成功處理器smsCodeAuthenticationFilter.setAuthenticationSuccessHandler(meicloudAuthenticationSuccessHandler);// 設置登錄失敗處理器smsCodeAuthenticationFilter.setAuthenticationFailureHandler(meicloudAuthenticationFailureHandler);String key = UUID.randomUUID().toString();smsCodeAuthenticationFilter.setRememberMeServices(new PersistentTokenBasedRememberMeServices(key, userDetailsService, persistentTokenRepository));SmsCodeAuthenticationProvider smsCodeAuthenticationProvider = new SmsCodeAuthenticationProvider();smsCodeAuthenticationProvider.setUserDetailsService(userDetailsService);// 將自己寫的Provider加到Provider集合里去http.authenticationProvider(smsCodeAuthenticationProvider).addFilterAfter(smsCodeAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);}}

BrowserSecurityConfig

作用:主配置類;添加短信驗證碼配置類、添加SmsCodeAuthenticationSecurityConfig配置

@Configurationpublic class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Autowiredprivate SecurityProperties securityProperties;@Autowiredprivate DataSource dataSource;@Autowiredprivate UserDetailsService userDetailsService;@Autowiredprivate AuthenticationSuccessHandler meicloudAuthenticationSuccessHandler;@Autowiredprivate AuthenticationFailureHandler meicloudAuthenticationFailureHandler;@Autowiredprivate SmsCodeAuthenticationSecurityConfig smsCodeAuthenticationSecurityConfig;@Overrideprotected void configure(HttpSecurity http) throws Exception {// 驗證碼校驗過濾器ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter();// 將驗證碼校驗過濾器加到 UsernamePasswordAuthenticationFilter 過濾器之前http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class).formLogin()// 當用戶登錄認證時默認跳轉的頁面.loginPage('/authentication/require')// 以下這行 UsernamePasswordAuthenticationFilter 會知道要處理表單的 /authentication/form 請求,而不是默認的 /login.loginProcessingUrl('/authentication/form').successHandler(meicloudAuthenticationSuccessHandler).failureHandler(meicloudAuthenticationFailureHandler)// 配置記住我功能.and().rememberMe()// 配置TokenRepository.tokenRepository(persistentTokenRepository())// 配置Token過期時間.tokenValiditySeconds(3600)// 最終拿到用戶名之后,使用UserDetailsService去做登錄.userDetailsService(userDetailsService).and().authorizeRequests()// 排除對 '/authentication/require' 和 '/meicloud-signIn.html' 的身份驗證.antMatchers('/authentication/require', securityProperties.getBrowser().getSignInPage(), '/code/*').permitAll()// 表示所有請求都需要身份驗證.anyRequest().authenticated().and().csrf().disable()// 暫時把跨站請求偽造的功能關閉掉// 相當于把smsCodeAuthenticationSecurityConfig里的配置加到上面這些配置的后面.apply(smsCodeAuthenticationSecurityConfig);}/** * 記住我功能的Token存取器配置 * * @return */@Beanpublic PersistentTokenRepository persistentTokenRepository() {JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();tokenRepository.setDataSource(dataSource);// 啟動的時候自動創建表,建表語句 JdbcTokenRepositoryImpl 已經都寫好了tokenRepository.setCreateTableOnStartup(true);return tokenRepository;}}

總結

到此這篇關于Spring Security 實現短信驗證碼登錄功能的文章就介紹到這了,更多相關spring security 驗證碼登錄內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!

標簽: Spring
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
九九综合在线| 国产精品久久久久久久久久久久久久久| 蜜臀精品久久久久久蜜臀 | 成人小电影网站| 久久国产毛片| 亚洲欧美日韩综合国产aⅴ| 在线精品小视频| 日韩有吗在线观看| 精品国产中文字幕第一页| 精品国产精品久久一区免费式| 麻豆91精品视频| 五月天激情综合网| 国产精品流白浆在线观看| 久久久777| 亚洲三级av| 日韩欧美精品一区| 亚洲欧美日韩国产综合精品二区| 中文字幕成人| 电影天堂国产精品| 国产精品久久久网站| 久久中文字幕av| 免播放器亚洲| yellow在线观看网址| 91成人小视频| 亚洲三级精品| 美女少妇全过程你懂的久久| 久久中文字幕一区二区三区| 在线精品视频一区| 精品成av人一区二区三区| 亚洲三级观看| 91久久午夜| 久久久久午夜电影| 日韩中文欧美| 国产毛片精品久久| 亚洲在线成人| 免费毛片在线不卡| 久久人人精品| 亚洲专区欧美专区| 97视频热人人精品免费| 中文字幕日韩高清在线| 九九精品调教| 国产一区二区三区视频在线| 亚洲精品乱码日韩| 激情婷婷亚洲| 成人午夜毛片| 国产精品日本一区二区不卡视频| 欧美.日韩.国产.一区.二区| 精品亚洲a∨一区二区三区18| 亚洲精品动态| 亚洲一区av| 综合亚洲视频| 天堂av在线一区| 最新国产拍偷乱拍精品| 欧美日韩国产v| 国产在线一区不卡| 麻豆高清免费国产一区| 国产精品日韩精品在线播放| 91成人小视频| 日本国产精品| 精品一区欧美| 精品亚洲成人| 久久69成人| 精品日韩一区| 精品一区二区三区视频在线播放 | 国产精品一区二区中文字幕| 蜜桃久久精品一区二区| 99在线精品免费视频九九视 | 亚洲91在线| 亚洲+小说+欧美+激情+另类| 亚洲三级精品| 免费一级欧美片在线观看网站| 六月丁香综合在线视频| 日产精品一区二区| 欧美亚洲精品在线| 蜜臀av在线播放一区二区三区| 日韩影片在线观看| 国产精品一区二区三区四区在线观看 | 亚洲黑丝一区二区| 精精国产xxxx视频在线野外| 精品免费av在线| 高清av不卡| 国产精品xxxav免费视频| 日本欧美大码aⅴ在线播放| 亚洲精品在线二区| 日韩精品a在线观看91| 亚洲bt欧美bt精品777| 伊人www22综合色| 亚洲精品自拍| 欧美一区成人| 亚洲精品系列| 中文字幕av亚洲精品一部二部| 国产精品日本一区二区三区在线 | 亚洲精品动态| 久久wwww| 福利在线一区| 亚洲欧美久久久| 在线日韩成人| 日韩高清成人在线| 日韩国产专区| 国产精品一国产精品k频道56| 91精品蜜臀一区二区三区在线| 久久不射网站| 日韩中文欧美| 国内在线观看一区二区三区| 久久精选视频| 嫩草伊人久久精品少妇av杨幂 | 日本精品影院| 日韩激情综合| 九九久久电影| 精品国产不卡一区二区| 免费不卡在线视频| 欧美国产另类| 美女久久久久| 青草国产精品| 久久人人精品| 久久狠狠久久| 激情偷拍久久| 日本一区二区高清不卡| 丝袜美腿高跟呻吟高潮一区| 欧美精品国产白浆久久久久| 色吊丝一区二区| 国产日韩欧美三区| 亚洲在线观看| 欧美特黄一区| 99成人超碰| 亚洲午夜黄色| 国产成人免费| 国产精品亚洲四区在线观看| 国产aⅴ精品一区二区三区久久| 欧美视频二区| 蜜臀av一区二区三区| 日韩精品一级二级| 一区二区三区国产盗摄| 尤物精品在线| 日韩午夜在线| 午夜电影亚洲| 欧美成人高清| 亚州av乱码久久精品蜜桃| 极品裸体白嫩激情啪啪国产精品| 五月婷婷六月综合| 久久最新视频| 综合激情一区| 欧美日韩网址| 精品国内亚洲2022精品成人| 欧美久久亚洲| 精品精品国产三级a∨在线| 亚洲黄色免费看| 亲子伦视频一区二区三区| 一本色道久久精品| 一本综合精品| 国产精品红桃| 99热国内精品| 久久国产66| 久久99久久久精品欧美| 亚洲天堂av影院| 国产女优一区| 麻豆国产一区| 亚洲福利久久| 亚洲a级精品| 老司机免费视频一区二区| 麻豆91在线播放| 免费av一区二区三区四区| 欧美一区成人| 国产一区二区三区四区| 天堂va蜜桃一区二区三区| 国产福利资源一区| 久久久噜噜噜| 日本不卡在线视频| 日韩精品水蜜桃| 亚州精品视频| jizzjizz中国精品麻豆| 人人精品人人爱| 日韩欧美三级| 91成人在线| 三上悠亚国产精品一区二区三区| 日韩精品免费视频人成| 亚洲国产不卡| 精精国产xxxx视频在线播放| 欧美日韩18| 亚洲精品极品| 亚洲精选91| 亚洲一区二区免费在线观看| 欧美精品一区二区久久| 成人日韩在线| 福利一区视频| 亚洲伊人av| 成人在线超碰| 精品国产午夜肉伦伦影院| 国产精品日韩久久久| 国产一区观看| 久久久精品午夜少妇| 欧美日韩在线观看首页| 国产精品99在线观看| 国产精品久久久久久久久久白浆 | 在线亚洲自拍| 国产精品色网| 亚洲欧美日韩专区| 色爱av综合网| 99国产精品久久久久久久成人热| 黄色不卡一区|