Spring security usage classification:
I believe everyone who has lived in Baidu knows how to use spring security. There are four usages, from simple to deep:
1. No database is used, all data is written in the configuration file, which is also a demo in the official document;
2. Use the database and implement the default code design of the database according to spring security, which means that the database has been fixed, this method is inflexible, and the database is designed very simple and has poor practicality;
3. Spring security is different from Acegi. It cannot modify the default filter anymore, but it supports inserting filters, so based on this, we can insert our own filters for flexibly use;
4. Violent means to modify the source code. The modification of the default filter mentioned above is just to modify the configuration file to replace the filter. This directly changes the source code inside, but this does not conform to the OO design principle, and is not practical and unavailable.
This article mainly introduces relevant content about spring security custom authentication login. It is shared for your reference and learning. I won’t say much below. Let’s take a look at the detailed introduction together.
1. Summary
1.1. Introduction
spring security is a security framework based on Spring AOP and Servlet filters to manage permission authentication, etc.
1.2.spring security custom authentication process
1) Authentication process
Generate unauthenticated AuthenticationTokens
↑ (Get information) (Assign providers according to AuthenticationToken) AuthenticationFilter -> AuthenticationManager -> AuthenticationProvider ↓ (Authentication) UserDetails (General query database acquisition) ↓ (Pass) Generate AuthenticationToken that has been successfully authenticated ↓ (Storage) SecurityContextHolder
2) Add AuthenticationFilter to the security filter chain (configured in the resource server), such as:
http.addFilterBefore(AuthenticationFilter, AbstractPreAuthenticatedProcessingFilter.class)
or:
http.addFilterAfter(AuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
2. Take SMS login as an example
2.1. Development environment
2.2. Core code analysis
2.2.1. Custom login authentication process
2.2.1.1. Custom authentication login token
/** * Mobile login Token * * @author : CatalpaFlat */public class MobileLoginAuthenticationToken extends AbstractAuthenticationToken { private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID; private static final Logger logger = LoggerFactory.getLogger(MobileLoginAuthenticationToken.class.getName()); private final Object principal; public MobileLoginAuthenticationToken(String mobile) { super(null); this.principal = mobile; this.setAuthenticated(false); logger.info("MobileLoginAuthenticationToken setAuthenticated ->false loading..."); } public MobileLoginAuthenticationToken(Object principal, Collection<? extends GrantedAuthority> authorities) { super(authorities); this.principal = principal; // must use super, as we override super.setAuthenticated(true); logger.info("MobileLoginAuthenticationToken setAuthenticated ->true loading..."); } @Override public void setAuthenticated(boolean authenticated) { if (authenticated) { throw new IllegalArgumentException( "Cannot set this token to trusted - use constructor which takes a GrantedAuthentication list instead"); } super.setAuthenticated(false); } @Override public Object getCredentials() { return null; } @Override public Object getPrincipal() { return this.principal; } @Override public void eraseCredentials() { super.eraseCredentials(); }} Note:
setAuthenticated(): determines whether it has been authenticated
2.2.1.1. Custom authentication login filter
/** * Mobile SMS Login Filter* * @author: CatalpaFlat */public class MobileLoginAuthenticationFilter extends AbstractAuthenticationProcessingFilter { private boolean postOnly = true; private static final Logger logger = LoggerFactory.getLogger(MobileLoginAuthenticationFilter.class.getName()); @Getter @Setter private String mobileParameterName; public MobileLoginAuthenticationFilter(String mobileLoginUrl, String mobileParameterName, String httpMethod) { super(new AntPathRequestMatcher(mobileLoginUrl, httpMethod)); this.mobileParameterName = mobileParameterName; logger.info("MobileLoginAuthenticationFilter loading..."); } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException { if (postOnly && !request.getMethod().equals(HttpMethod.POST.name())) { throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod()); } //get mobile String mobile = obtainMobile(request); //assemble token MobileLoginAuthenticationToken authRequest = new MobileLoginAuthenticationToken(mobile); // Allow subclasses to set the "details" property setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); } /** * Details for setting identity authentication*/ private void setDetails(HttpServletRequest request, MobileLoginAuthenticationToken authRequest) { authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); } /** * Get mobile number*/ private String obtainMobile(HttpServletRequest request) { return request.getParameter(mobileParameterName); } public void setPostOnly(boolean postOnly) { this.postOnly = postOnly; }}Note: attemptAuthentication() method:
2.2.1.1. Custom authentication login provider
/** * Mobile SMS Login Authentication Provider* * @author: CatalpaFlat */public class MobileLoginAuthenticationProvider implements AuthenticationProvider { private static final Logger logger = LoggerFactory.getLogger(MobileLoginAuthenticationProvider.class.getName()); @Getter @Setter private UserDetailsService customUserDetailsService; public MobileLoginAuthenticationProvider() { logger.info("MobileLoginAuthenticationProvider loading ..."); } /** * Authentication*/ @Override public Authentication authentication(Authentication authentication) throws AuthenticationException { //Get the token information encapsulated by the filter MobileLoginAuthenticationToken authenticationToken = (MobileLoginAuthenticationToken) authentication; //Get user information (database authentication) UserDetails userDetails = customUserDetailsService.loadUserByUsername((String) authenticationToken.getPrincipal()); //Not passed if (userDetails == null) { throw new InternalAuthenticationServiceException("Unable to obtain user information"); } //By MobileLoginAuthenticationToken authenticationResult = new MobileLoginAuthenticationToken(userDetails, userDetails.getAuthorities()); authenticationResult.setDetails(authenticationToken.getDetails()); return authenticationResult; } /** * According to the token type, determine which Provider to use */ @Override public boolean supports(Class<?> authentication) { return MobileLoginAuthenticationToken.class.isAssignableFrom(authentication); }}Note: authenticate() method
2.2.1.1. Custom authentication login authentication configuration
@Configuration(SpringBeanNameConstant.DEFAULT_CUSTOM_MOBILE_LOGIN_AUTHENTICATION_SECURITY_CONFIG_BN)public class MobileLoginAuthenticationSecurityConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> { private static final Logger logger = LoggerFactory.getLogger(MobileLoginAuthenticationSecurityConfig.class.getName()); @Value("${login.mobile.url}") private String defaultMobileLoginUrl; @Value("${login.mobile.parameter}") private String defaultMobileLoginParameter; @Value("${login.mobile.httpMethod}") private String defaultMobileLoginHttpMethod; @Autowired private CustomYmlConfig customYmlConfig; @Autowired private UserDetailsService customUserDetailsService; @Autowired private AuthenticationSuccessHandler customAuthenticationSuccessHandler; @Autowired private AuthenticationFailureHandler customAuthenticationFailureHandler; public MobileLoginAuthenticationSecurityConfig() { logger.info("MobileLoginAuthenticationSecurityConfig loading..."); } @Override public void configure(HttpSecurity http) throws Exception { MobilePOJO mobile = customYmlConfig.getLogins().getMobile(); String url = mobile.getUrl(); String parameter = mobile.getParameter().getMobile(); String httpMethod = mobile.getHttpMethod(); MobileLoginAuthenticationFilter mobileLoginAuthenticationFilter = new MobileLoginAuthenticationFilter(StringUtils.isBlank(url) ? defaultMobileLoginUrl : url, StringUtils.isBlank(parameter) ? defaultMobileLoginUrl : parameter, StringUtils.isBlank(httpMethod) ? defaultMobileLoginHttpMethod : httpMethod); mobileLoginAuthenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class)); mobileLoginAuthenticationFilter.setAuthenticationSuccessHandler(customAuthenticationSuccessHandler); mobileLoginAuthenticationFilter.setAuthenticationFailureHandler(customAuthenticationFailureHandler); MobileLoginAuthenticationProvider mobileLoginAuthenticationProvider = new MobileLoginAuthenticationProvider(); mobileLoginAuthenticationProvider.setCustomUserDetailsService(customUserDetailsService); http.authenticationProvider(mobileLoginAuthenticationProvider) .addFilterAfter(mobileLoginAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); }}Note: configure() method
Instantiate AuthenticationFilter and AuthenticationProvider
Add AuthenticationFilter and AuthenticationProvider to spring security.
2.2.2. Verify custom verification code based on redis
2.2.2.1. Custom verification code filter based on redis
/** * Verification code filter* * @author: CatalpaFlat */@Component(SpringBeanNameConstant.DEFAULT_VALIDATE_CODE_FILTER_BN)public class ValidateCodeFilter extends OncePerRequestFilter implements InitializingBean { private static final Logger logger = LoggerFactory.getLogger(ValidateCodeFilter.class.getName()); @Autowired private CustomYmlConfig customYmlConfig; @Autowired private RedisTemplate<Object, Object> redisTemplate; /** * Tool class that verifys whether the requested url matches the configured url*/ private AntPathMatcher pathMatcher = new AntPathMatcher(); public ValidateCodeFilter() { logger.info("Loading ValidateCodeFilter..."); } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String url = customYmlConfig.getLogins().getMobile().getUrl(); if (pathMatcher.match(url, request.getRequestURI())) { String deviceId = request.getHeader("deviceId"); if (StringUtils.isBlank(deviceId)) { throw new CustomException(HttpStatus.NOT_ACCEPTABLE.value(), "Not deviceId in the head of the request"); } String codeParamName = customYmlConfig.getLogins().getMobile().getParameter().getCode(); String code = request.getParameter(codeParamName); if (StringUtils.isBlank(code)) { throw new CustomException(HttpStatus.NOT_ACCEPTABLE.value(), "Not code in the parameters of the request"); } String key = SystemConstant.DEFAULT_MOBILE_KEY_PIX + deviceId; SmsCodePO smsCodePo = (SmsCodePO) redisTemplate.opsForValue().get(key); if (smsCodePo.isExpried()){ throw new CustomException(HttpStatus.BAD_REQUEST.value(), "The verification code has expired"); } String smsCode = smsCodePo.getCode(); if (StringUtils.isBlank(smsCode)) { throw new CustomException(HttpStatus.BAD_REQUEST.value(), "Verification code does not exist"); } if (StringUtils.equals(code, smsCode)) { redisTemplate.delete(key); //let it go filterChain.doFilter(request, response); } else { throw new CustomException(HttpStatus.BAD_REQUEST.value(), "Validation code is incorrect"); } }else { //let it go filterChain.doFilter(request, response); } }}Note: doFilterInternal()
Custom verification code filter verification
2.2.2.2. Add custom verification code filter to spring security filter chain
http.addFilterBefore(validateCodeFilter, AbstractPreAuthenticatedProcessingFilter.class)
Note: Before adding to the authentication preprocessing filter
3. Test the effect
Finally, the source code address is attached: https://gitee.com/CatalpaFlat/springSecurity.git (local download)
Summarize
The above is the entire content of this article. I hope that the content of this article has certain reference value for everyone's study or work. If you have any questions, you can leave a message to communicate. Thank you for your support to Wulin.com.