Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

An example Analysis of SMS Login Development for Spring Security parsing

2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)06/02 Report--

Today, I will talk to you about the example analysis of SMS login development for Spring Security parsing. Many people may not know much about it. In order to make you understand better, the editor summarized the following content for you. I hope you can get something according to this article.

Spring Security parsing-- SMS login development

> when learning Spring Cloud,    always has little knowledge of oauth related to authorization service, so he decides to first study and sort through the permissions such as Spring Security, Spring Security Oauth3, authentication-related content, principles and design. This series of articles is written to strengthen the impression and understanding in the process of learning. Please let me know if there is any infringement.

> Project environment: >-JDK1.8 >-Spring boot 2.x >-Spring Security 5.x

First, how to achieve SMS login function on the basis of Security?

   reviews the process of implementing form login with Security:

From the    process, we found that it has special processing or other sister implementation subclasses in the login process: >-AuthenticationFilter: used to intercept login requests; >-unauthenticated Authentication object as an input parameter of the authentication method; >-AuthenticationProvider for authentication processing.

   so we can completely customize a SmsAuthenticationFilter to intercept, a SmsAuthenticationToken to transmit authentication data, and a SmsAuthenticationProvider to process authentication business. Because we know that UsernamePasswordAuthenticationFilter's doFilter is implemented through AbstractAuthenticationProcessingFilter, while UsernamePasswordAuthenticationFilter itself only implements the attemptAuthentication () method. According to this design, our SmsAuthenticationFilter only implements the attemptAuthentication () method, so how to verify the CAPTCHA? At this point, we need to call a verification filter filter: ValidateCodeFilter that implements the CAPTCHA before the SmsAuthenticationFilter. The process after collation and implementation is shown below:

2. The development of SMS login authentication (1) SmsAuthenticationFilter implementation

After    simulates UsernamePasswordAuthenticationFilter to implement SmsAuthenticationFilter, the code is as follows:

@ EqualsAndHashCode (callSuper = true) @ Datapublic class SmsCodeAuthenticationFilter extends AbstractAuthenticationProcessingFilter {/ / get the parameter name private String mobileParameter = SecurityConstants.DEFAULT_PARAMETER_NAME_MOBILE; private boolean postOnly = true; / / constructor that passes the mobile phone number in request, and mainly configure the request address url public SmsCodeAuthenticationFilter () {super (SecurityConstants.DEFAULT_LOGIN_PROCESSING_URL_MOBILE (SecurityConstants.DEFAULT_LOGIN_PROCESSING_URL_MOBILE, "POST")) to be intercepted by its interceptor } @ Override public Authentication attemptAuthentication (HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {/ / determine whether the request is in POST mode if (postOnly & &! request.getMethod (). Equals ("POST")) {throw new AuthenticationServiceException ("Authentication method not supported:" + request.getMethod ());} / / call the obtainMobile method to get the mobile phone number String mobile = obtainMobile (request) from request If (mobile = = null) {mobile = ";} mobile = mobile.trim (); / / create an unauthenticated SmsCodeAuthenticationToken object SmsCodeAuthenticationToken authRequest = new SmsCodeAuthenticationToken (mobile); setDetails (request, authRequest); / / call authentication method return this.getAuthenticationManager () .authenticate (authRequest) } / * get the mobile phone number * / protected String obtainMobile (HttpServletRequest request) {return request.getParameter (mobileParameter);} / * the implementation of copying UsernamePasswordAuthenticationFilter intact (note here is SmsCodeAuthenticationToken) * / protected void setDetails (HttpServletRequest request, SmsCodeAuthenticationToken authRequest) {authRequest.setDetails (authenticationDetailsSource.buildDetails (request)) } / * Open the set method of setting RemmemberMeServices * / @ Override public void setRememberMeServices (RememberMeServices rememberMeServices) {super.setRememberMeServices (rememberMeServices);}}

There are several points for attention in its internal implementation: >-set the parameter properties of the transmission mobile phone number >-the constructor calls the parameter construction method of the parent class, which is mainly used to set the url to be intercepted >-copy the implementation of attemptAuthentication () of UsernamePasswordAuthenticationFilter, which needs to be modified in two points: 1. ObtainMobile to obtain mobile phone number information 2, create SmsCodeAuthenticationToken object >-in order to achieve SMS login, it also has the function of remembering me. The setRememberMeServices () method is opened here to set the rememberMeServices.

(2) SmsAuthenticationToken implementation

Like   , we simulate UsernamePasswordAuthenticationToken to implement SmsAuthenticationToken:

If public class SmsCodeAuthenticationToken extends AbstractAuthenticationToken {private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID; private final Object principal; / * is not authenticated, the content is mobile number * @ param mobile * / public SmsCodeAuthenticationToken (String mobile) {super (null); this.principal = mobile; setAuthenticated (false) } / * * after successful authentication, the user information * * @ param principal * @ param authorities * / public SmsCodeAuthenticationToken (Object principal, Collection authorities) {super (authorities); this.principal = principal; super.setAuthenticated (true) } @ Override public Object getCredentials () {return null;} @ Override public Object getPrincipal () {return this.principal;} @ Override public 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) @ Override public void eraseCredentials () {super.eraseCredentials ();}}

   compared to UsernamePasswordAuthenticationToken, we reduced the credentials (can be understood as a password), the rest is basically intact.

(3) SmsAuthenticationProvider implementation

   because SmsCodeAuthenticationProvider is a new and different implementation of authentication delegation, so we write this according to our own imagination, without referring to DaoAuthenticationProvider. Take a look at the code we implemented ourselves:

@ Datapublic class SmsCodeAuthenticationProvider implements AuthenticationProvider {private UserDetailsService userDetailsService; @ Override public Authentication authenticate (Authentication authentication) throws AuthenticationException {SmsCodeAuthenticationToken authenticationToken = (SmsCodeAuthenticationToken) authentication; UserDetails user = userDetailsService.loadUserByUsername ((String) authenticationToken.getPrincipal ()); if (user = = null) {throw new InternalAuthenticationServiceException ("unable to get user information");} SmsCodeAuthenticationToken authenticationResult = new SmsCodeAuthenticationToken (user, user.getAuthorities ()) AuthenticationResult.setDetails (authenticationToken.getDetails ()); return authenticationResult;} @ Override public boolean supports (Class authentication) {return SmsCodeAuthenticationToken.class.isAssignableFrom (authentication);}}

   implements its interface methods authenticate () and supports () by directly inheriting from AuthenticationProvider. Supports () We refer directly to other Provider, which is mainly to determine whether the currently processed Authentication is SmsCodeAuthenticationToken or its subclass. Authenticate () We simply implement it by calling the loadUserByUsername () method of userDetailsService, because the verification code has been verified in ValidateCodeFilter, so as long as we can query the user information through the mobile phone number, we will directly determine the success of the current user authentication and generate an authenticated SmsCodeAuthenticationToken return.

(4) ValidateCodeFilter implementation

  , as we described earlier, ValidateCodeFilter only verifies the verification code. Here, we set the verification code generated through redis to compare the verification code entered by the user:

@ Componentpublic class ValidateCodeFilter extends OncePerRequestFilter implements InitializingBean {/ * verification failed processor * / @ Autowired private AuthenticationFailureHandler authenticationFailureHandler; / * system configuration information * / @ Autowired private SecurityProperties securityProperties; @ Resource private StringRedisTemplate stringRedisTemplate; / * store all url * / private Map urlMap = new HashMap () that need a verification code / * tool class to verify whether the request url matches the configured url * / private AntPathMatcher pathMatcher = new AntPathMatcher (); / * initialize the url configuration information to be intercepted * / @ Override public void afterPropertiesSet () throws ServletException {super.afterPropertiesSet (); urlMap.put (SecurityConstants.DEFAULT_LOGIN_PROCESSING_URL_MOBILE, SecurityConstants.DEFAULT_PARAMETER_NAME_CODE_SMS) AddUrlToMap (securityProperties.getSms (). GetSendSmsUrl (), SecurityConstants.DEFAULT_PARAMETER_NAME_CODE_SMS) } / * the URL configured in the system that requires verification code is put into map * * @ param urlString * @ param smsParam * / protected void addUrlToMap (String urlString, String smsParam) {if (StringUtils.isNotBlank (urlString)) {String [] urls = StringUtils.splitByWholeSeparatorPreserveAllTokens (urlString, ",") according to the type of verification For (String url: urls) {urlMap.put (url, smsParam);}} @ Override protected void doFilterInternal (HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {String code = request.getParameter (getValidateCode (request)) If (code! = null) {try {String oldCode = stringRedisTemplate.opsForValue () .get (request.getParameter (SecurityConstants.DEFAULT_PARAMETER_NAME_MOBILE)); if (StringUtils.equalsIgnoreCase (oldCode,code)) {logger.info ("CAPTCHA passed") } else {throw new ValidateCodeException ("CAPTCHA invalidation or error!") ;} catch (AuthenticationException e) {authenticationFailureHandler.onAuthenticationFailure (request, response, e); return;}} chain.doFilter (request, response) } / * get the check code * * @ param request * @ return * / private String getValidateCode (HttpServletRequest request) {String result = null; if (! StringUtils.equalsIgnoreCase (request.getMethod (), "get")) {Set urls = urlMap.keySet () For (String url: urls) {if (pathMatcher.match (url, request.getRequestURI () {result = urlMap.get (url);} return result;}}

Here we mainly look at doFilterInternal to implement CAPTCHA verification logic.

3. How to add the Filter that sets SMS to the FilterChain to take effect?

Here we need to introduce a new configuration class SmsCodeAuthenticationSecurityConfig. In fact, the code is as follows:

@ Componentpublic class SmsCodeAuthenticationSecurityConfig extends SecurityConfigurerAdapter {@ Autowired private AuthenticationSuccessHandler authenticationSuccessHandler; @ Autowired private AuthenticationFailureHandler authenticationFailureHandler; @ Resource private UserDetailsService userDetailsService; @ Override public void configure (HttpSecurity http) throws Exception {SmsCodeAuthenticationFilter smsCodeAuthenticationFilter = new SmsCodeAuthenticationFilter (); / / set AuthenticationManager smsCodeAuthenticationFilter.setAuthenticationManager (http.getSharedObject (AuthenticationManager.class)); / / set success and failure processors smsCodeAuthenticationFilter.setAuthenticationSuccessHandler (authenticationSuccessHandler) and smsCodeAuthenticationFilter.setAuthenticationFailureHandler (authenticationFailureHandler) respectively / / set RememberMeServices smsCodeAuthenticationFilter.setRememberMeServices (http .getSharedObject (RememberMeServices.class)); / / create SmsCodeAuthenticationProvider and set userDetailsService SmsCodeAuthenticationProvider smsCodeAuthenticationProvider = new SmsCodeAuthenticationProvider (); smsCodeAuthenticationProvider.setUserDetailsService (userDetailsService) / / add Provider to it http.authenticationProvider (smsCodeAuthenticationProvider) / / add filter after UsernamePasswordAuthenticationFilter .addFilterAfter (smsCodeAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);}

Finally, we need to reference SmsCodeAuthenticationSecurityConfig in the SpringSecurityConfig configuration class:

Http.addFilterBefore (validateCodeFilter, AbstractPreAuthenticatedProcessingFilter.class). Apply (smsCodeAuthenticationSecurityConfig). ... Add CAPTCHA API and CAPTCHA login form

   added the API for sending CAPTCHA (mainly set to no permission to access):

@ GetMapping ("/ send/sms/ {mobile}") public void sendSms (@ PathVariable String mobile) {/ / randomly generate a 6-digit number string String code = RandomStringUtils.randomNumeric (6); / / stringRedisTemplate.opsForValue () .set (mobile, code, 60 * 5, TimeUnit.SECONDS) in redis via stringRedisTemplate cache / / simulate sending SMS verification code log.info ("send SMS verification code to mobile phone:" + mobile + "is" + code);}

   added CAPTCHA login form:

/ / Note that the request API here should be consistent with the mobile number set by the constructor of SmsAuthenticationFilter: SMS verification code: send verification code to remember me. Login 5. Personal summary

   actually implements another login method, and the key point lies in the three points with filter, AuthenticationToken, and AuthenticationProvider. Sort it out is: intercept through a custom SmsAuthenticationFilter, an AuthenticationToken to transmit authentication data, an AuthenticationProvider for authentication business processing. Because we know that UsernamePasswordAuthenticationFilter's doFilter is implemented through AbstractAuthenticationProcessingFilter, while UsernamePasswordAuthenticationFilter itself only implements the attemptAuthentication () method. In this design, our AuthenticationFilter only implements the attemptAuthentication () method, but we also need to call an implementation validation filtering filter: ValidatFilter before AuthenticationFilter. As in the following flowchart, you can add any login method in this way:

   this article introduces the code developed by SMS login that can access the security module in the code repository. The github address of the project: http.

After reading the above, do you have any further understanding of the example analysis of SMS login development for Spring Security parsing? If you want to know more knowledge or related content, please follow the industry information channel, thank you for your support.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report