Now there are three main login methods: account password login, SMS verification code login and third-party authorized login. The previous section Spring security (3) -- authentication process We have analyzed the spring security account password mode login. Now let's analyze the spring security SMS mode authentication login.
Custom Filter:
Custom Authentication
Custom AuthenticationProvider
Custom UserDetailsService
SecurityConfig configuration
1. User defined filter:
Build the constructor and filter the request path and request mode in the constructor
Custom attemptAuthentication() authentication steps
In step 2, the authentication provider is required for final authentication. In the authentication filter, the AuthenticationProvider needs to be set into the filter, while the AuthenticationManager is used to manage the AuthenticationProvider. Therefore, when creating the filter filter, we need to set the AuthenticationManager. This step is detailed in the 5.1 SecurityConfig configuration step.
In step 2, the attamptauthentication() authentication method mainly performs the following steps:
1).post request authentication;
2).request to obtain mobile phone number and verification code;
3). Encapsulate mobile phone number and verification code with user-defined Authentication object;
4). Use the AuthenticationManager.authenticate() method to verify.
Custom filter implementation code:
public class SmsAuthenticationfilter extends AbstractAuthenticationProcessingFilter { private boolean postOnly = true; public SmsAuthenticationfilter() { super(new AntPathRequestMatcher(SecurityConstants.APP_MOBILE_LOGIN_URL, "POST")); } [@Override](https://my.oschina.net/u/1162528) public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException { if (postOnly && !request.getMethod().equals("POST")) { throw new AuthenticationServiceException( "Authentication method not supported: " + request.getMethod()); } Assert.hasText(SecurityConstants.MOBILE_NUMBER_PARAMETER, "mobile parameter must not be empty or null"); String mobile = request.getParameter(SecurityConstants.MOBILE_NUMBER_PARAMETER); String smsCode = request.ge+tParameter(SecurityConstants.MOBILE_VERIFY_CODE_PARAMETER); if (mobile == null) { mobile=""; } if(smsCode == null){ smsCode=""; } mobile = mobile.trim(); smsCode = smsCode.trim(); SmsAuthenticationToken authRequest = new SmsAuthenticationToken(mobile,smsCode); // Allow subclasses to set the "details" property setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); }protected void setDetails(HttpServletRequest request, SmsAuthenticationToken authRequest) { authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); } public void setPostOnly(boolean postOnly) { this.postOnly = postOnly; } }
2. Authentication:
. https://www.jianshu.com/p/5e19f3a9f6dd
Custom SmsAuthenticationToken:
public class SmsAuthenticationToken extends AbstractAuthenticationToken { private final Object principal; private Object credentials; public SmsAuthenticationToken(Object principal,Object credentials ) { super(null); this.principal = principal; this.credentials=credentials; setAuthenticated(false); } public SmsAuthenticationToken(Object principal, Object credentials,Collection<? extends GrantedAuthority> authorities) { super(null); this.principal = principal; this.credentials=credentials; setAuthenticated(true); } [@Override](https://my.oschina.net/u/1162528) public Object getCredentials() { return this.credentials=credentials; } [@Override](https://my.oschina.net/u/1162528) public Object getPrincipal() { return this.principal; } 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](https://my.oschina.net/u/1162528) public void eraseCredentials() { super.eraseCredentials(); } }
3.AuthenticationProvider
The final authentication policy entry of . You can write according to AbstractUserDetailsAuthenticationProvider to implement the AuthenticationProvider and MessageSourceAware interface. The authentication logic can define the implementation. Is Jiaozuo Guoyitang gastrointestinal hospital normal: http://jz.lieju.com/xuankeyiyuan/37174867.htm
Custom AuthenticationProvider:
public class SmsAuthenticationProvide implements AuthenticationProvider, MessageSourceAware { private UserDetailsService userDetailsService; private MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor(); [@Override](https://my.oschina.net/u/1162528) public void setMessageSource(MessageSource messageSource) { this.messages = new MessageSourceAccessor(messageSource); } @Override public Authentication authenticate(Authentication authentication) { Assert.isInstanceOf(SmsAuthenticationToken.class, authentication, messages.getMessage( "AbstractUserDetailsAuthenticationProvider.onlySupports", "Only UsernamePasswordAuthenticationToken is supported")); SmsAuthenticationToken authenticationToken = (SmsAuthenticationToken) authentication; //Save the authentication information in the SecurityContext for the UserDetailsService to verify SecurityContext context = SecurityContextHolder.getContext(); context.setAuthentication(authenticationToken); String mobile = (String) authenticationToken.getPrincipal(); if (mobile == null) { throw new InternalAuthenticationServiceException("can't obtain user info "); } mobile = mobile.trim(); //Verify and obtain user information UserDetails user = userDetailsService.loadUserByUsername(mobile); if (user == null) { throw new InternalAuthenticationServiceException("can't obtain user info "); } SmsAuthenticationToken smsAuthenticationToken = new SmsAuthenticationToken(user, user.getAuthorities()); return smsAuthenticationToken; } @Override public boolean supports(Class<?> authentication) { return (SmsAuthenticationToken.class.isAssignableFrom(authentication)); } public void setUserDetailsService(UserDetailsService userDetailsService) { this.userDetailsService = userDetailsService; } public UserDetailsService getUserDetailsService() { return userDetailsService; } }
4. UserDetailsService
. You can customize the authentication logic according to your project.
Custom UserDetailsService:
public class SmsUserDetailsService implements UserDetailsService { @Autowired private RedisUtil redisUtil; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { //Obtain the information (mobile number, verification code) required for authentication from SecurityContext SecurityContext context = SecurityContextHolder.getContext(); SmsAuthenticationToken authentication = (SmsAuthenticationToken) context.getAuthentication(); if(!additionalAuthenticationChecks(username,authentication)){ return null; } //Obtain the information of the corresponding user of the user's mobile number, including the authority, etc return new User("admin", "123456", Arrays.asList(new SimpleGrantedAuthority("admin"))); } public boolean additionalAuthenticationChecks(String mobile, SmsAuthenticationToken smsAuthenticationToken) { //Get the value verification code corresponding to the mobile key value in redis String smsCode = redisUtil.get(mobile).toString(); //Get the verification code submitted by the user String credentials = (String) smsAuthenticationToken.getCredentials(); if(StringUtils.isEmpty(credentials)){ return false; } if (credentials.equalsIgnoreCase(smsCode)) { return true; } return false; } }
5.SecurityConfig
5.1 configure SecurityConfig for Sms authentication component
Set the default AuthenticationManager (which can also be defined) to a custom filter
Set the custom UserDetailsService to the custom authenticationprovider for use
Add the filter to the filtering link to implement the filtering operation. (usually added before UsernamePasswordAuthenticationFilter)
Configure SmsAuthenticationSecurityConfig:
@Component public class SmsAuthenticationSecurityConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> { @Autowired private UserDetailsService userDetailsService; @Override public void configure(HttpSecurity http) throws Exception { //Create and configure a custom SmsAuthenticationfilter, SmsAuthenticationfilter smsAuthenticationfilter = new SmsAuthenticationfilter(); smsAuthenticationfilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class)); smsAuthenticationfilter.setAuthenticationSuccessHandler(customAuthenticationSuccessHandler()); smsAuthenticationfilter.setAuthenticationFailureHandler(customAuthenticationFailureHandler()); //Create and configure a custom smsauthenticationprovider SmsAuthenticationProvide smsAuthenticationProvide=new SmsAuthenticationProvide(); smsAuthenticationProvide.setUserDetailsService(userDetailsService); http.authenticationProvider(smsAuthenticationProvide); //Add filter to filter link http.addFilterAfter(smsAuthenticationfilter, UsernamePasswordAuthenticationFilter.class); } @Bean public CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler() { return new CustomAuthenticationSuccessHandler(); } @Bean public CustomAuthenticationFailureHandler customAuthenticationFailureHandler() { return new CustomAuthenticationFailureHandler(); } }
5.2 SecurityConfig main configuration
Please refer to Section 2 for the main SecurityConfig configuration Spring Security (2) - WebSecurityConfigurer configuration and filter order Configure.
SecurityConfig main configuration:
@Configurationpublic class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private SmsAuthenticationSecurityConfig smsAuthenticationSecurityConfig; @Autowired private CustomAuthenticationSuccessHandler authenticationSuccessHandler; @Autowired private CustomAuthenticationFailureHandler authenticationFailureHandler; @Override protected void configure(HttpSecurity http) throws Exception { http.headers().frameOptions().disable().and() .formLogin() .loginPage(SecurityConstants.APP_FORM_LOGIN_PAGE) //Configure custom URL for form login .loginProcessingUrl(SecurityConstants.APP_FORM_LOGIN_URL) .successHandler(authenticationSuccessHandler) .failureHandler(authenticationFailureHandler) .and() //Configure smsAuthenticationSecurityConfig .apply(smsAuthenticationSecurityConfig) .and() //Run through URL .authorizeRequests() .antMatchers(SecurityConstants.APP_MOBILE_VERIFY_CODE_URL, SecurityConstants.APP_USER_REGISTER_URL) .permitAll() .and() .csrf().disable(); } @Bean public ObjectMapper objectMapper(){ return new ObjectMapper(); } }
6. other
6.1 redis
RedisUtil tool class:
@Componentpublic class RedisUtil { @Autowired private RedisTemplate<String, Object> redisTemplate; /** * General cache access * * @param key key * @return value */ public Object get(String key) { return key == null ? null : redisTemplate.opsForValue().get(key); } /** * Normal cache put * * @param key key * @param value value * @return true Success false failure */ public boolean set(String key, Object value) { try { redisTemplate.opsForValue().set(key, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * Normal cache put and set time * * @param key key * @param value value * @param time Time (seconds) time should be greater than 0. If time is less than or equal to 0, infinite period will be set * @return true Success false failure */ public boolean set(String key, Object value, long time) { try { if (time > 0) { redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS); } else { set(key, value); } return true; } catch (Exception e) { e.printStackTrace(); return false; } } }
redisConfig configuration class:
@Configurationpublic class RedisConfig {@Autowiredprivate RedisProperties properties;@Bean@SuppressWarnings("all")@ConditionalOnClass(RedisConnectionFactory.class)public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, Object> template = new RedisTemplate<String, Object>(); template.setConnectionFactory(factory); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); //The key adopts String serialization template.setKeySerializer(stringRedisSerializer); //The key of hash also adopts String serialization template.setHashKeySerializer(stringRedisSerializer); //value serialization is jackson template.setValueSerializer(jackson2JsonRedisSerializer); //value serialization of hash adopts jackson template.setHashValueSerializer(jackson2JsonRedisSerializer); template.afterPropertiesSet(); return template; } @Bean @Qualifier("redisConnectionFactory") public RedisConnectionFactory redisConnectionFactory(){ RedisStandaloneConfiguration redisConfig = new RedisStandaloneConfiguration(); redisConfig.setHostName(properties.getHost()); redisConfig.setPort(properties.getPort()); redisConfig.setPassword(RedisPassword.of(properties.getPassword())); redisConfig.setDatabase(properties.getDatabase()); //redis connection pool data settings JedisClientConfiguration.JedisClientConfigurationBuilder builder = JedisClientConfiguration.builder(); if (this.properties.getTimeout() != null) { Duration timeout = this.properties.getTimeout(); builder.readTimeout(timeout).connectTimeout(timeout); } RedisProperties.Pool pool = this.properties.getJedis().getPool(); if (pool != null) { builder.usePooling().poolConfig(this.jedisPoolConfig(pool)); } JedisClientConfiguration jedisClientConfiguration = builder.build(); //Generate JedisConnectionFactory according to two configuration classes return new JedisConnectionFactory(redisConfig,jedisClientConfiguration); } private JedisPoolConfig jedisPoolConfig(RedisProperties.Pool pool) { JedisPoolConfig config = new JedisPoolConfig(); config.setMaxTotal(pool.getMaxActive()); config.setMaxIdle(pool.getMaxIdle()); config.setMinIdle(pool.getMinIdle()); if (pool.getMaxWait() != null) { config.setMaxWaitMillis(pool.getMaxWait().toMillis()); } return config; } }
7. summary
. In the future, there will be a case study of the third-party landing mode. Last error please comment!