Sample Code for adding a verification code to spring security4 and sample code for security4
Spring security is a large module. This article only covers the authentication of custom parameters. The default verification parameters of spring security are username and password, which are generally insufficient. Because it takes too long, I may forget it and may have some omissions. Okay, no nonsense.
Java config is used for spring and spring security configurations. The versions are 4.2.5 and 4.0.4 in sequence.
General idea: Customize EntryPoint, add custom parameter extension AuthenticationToken and AuthenticationProvider for verification.
First define EntryPoint:
import org.springframework.security.core.AuthenticationException;import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;public class MyAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint { public MyAuthenticationEntryPoint(String loginFormUrl) { super(loginFormUrl); } @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { super.commence(request, response, authException); }}
The next step is token, and validCode is the verification code parameter:
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;public class MyUsernamePasswordAuthenticationToken extends UsernamePasswordAuthenticationToken { private String validCode; public MyUsernamePasswordAuthenticationToken(String principal, String credentials, String validCode) { super(principal, credentials); this.validCode = validCode; } public String getValidCode() { return validCode; } public void setValidCode(String validCode) { this.validCode = validCode; }}
Continue ProcessingFilter,
Import com. core. shared. validateCodeHandle; import org. springframework. security. core. authentication; import org. springframework. security. core. authenticationException; import org. springframework. security. web. authentication. abstractAuthenticationProcessingFilter; import org. springframework. security. web. util. matcher. antPathRequestMatcher; import javax. servlet. servletException; import javax. servlet. http. httpS ErvletRequest; import javax. servlet. http. httpServletResponse; import javax. servlet. http. httpSession; import java. io. IOException; public class MyValidCodeProcessingFilter extends {private String usernameParam = "username"; private String passwordParam = "password"; private String validCodeParam = "validateCode"; public MyValidCodeProcessingFilter () {super (new Login ("/user/login", "POST") ;}@ Override public Authentication attemptAuthentication (HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {String username = request. getParameter (usernameParam); String password = request. getParameter (passwordParam); String validCode = request. getParameter (validCodeParam); valid (vali DCode, request. getSession (); MyUsernamePasswordAuthenticationToken token = new MyUsernamePasswordAuthenticationToken (username, password, validCode); return this. getAuthenticationManager (). authenticate (token);} public void valid (String validCode, HttpSession session) {if (validCode = null) {throw new ValidCodeErrorException ("the verification code is blank! ");} If (! ValidateCodeHandle. matchCode (session. getId (), validCode) {throw new ValidCodeErrorException ("Verification code error! ");}}}
Define three parameters for receiving parameters from the login form. The construction method provides the login url and the post method.
The next step is to authenticate the user name and password. The verification code has not been authenticated yet.
The following is a tool class and ValidCodeErrorException of ValidateCodeHandle:
import java.util.concurrent.ConcurrentHashMap;public class ValidateCodeHandle { private static ConcurrentHashMap validateCode = new ConcurrentHashMap<>(); public static ConcurrentHashMap getCode() { return validateCode; } public static void save(String sessionId, String code) { validateCode.put(sessionId, code); } public static String getValidateCode(String sessionId) { Object obj = validateCode.get(sessionId); if (obj != null) { return String.valueOf(obj); } return null; } public static boolean matchCode(String sessionId, String inputCode) { String saveCode = getValidateCode(sessionId); if (saveCode.equals(inputCode)) { return true; } return false; }}
AuthenticationException must be inherited to indicate that it is a security authentication failure, so that the subsequent failure process will be followed.
import org.springframework.security.core.AuthenticationException;public class ValidCodeErrorException extends AuthenticationException { public ValidCodeErrorException(String msg) { super(msg); } public ValidCodeErrorException(String msg, Throwable t) { super(msg, t); }}
The following is Provider:
Import org. springframework. security. authentication. badCredentialsException; import org. springframework. security. authentication. usernamePasswordAuthenticationToken; import org. springframework. security. authentication. dao. daoAuthenticationProvider; import org. springframework. security. core. authenticationException; import org. springframework. security. core. userdetails. userDetails; public class MyAuthenticatio NProvider extends DaoAuthenticationProvider {@ Override public boolean supports (Class <?> Authentication) {return authentication. class. isAssignableFrom (authentication) ;}@ Override protected void encode (UserDetails userDetails, authentication) throws AuthenticationException {Object salt = null; if (getSaltSource ()! = Null) {salt = getSaltSource (). getSalt (userDetails);} if (authentication. getCredentials () = null) {logger. debug ("Authentication failed: no credentials provided"); throw new BadCredentialsException ("the user name or password is incorrect! ");} String presentedPassword = authentication. getCredentials (). toString (); if (! This. getPasswordEncoder (). isPasswordValid (userDetails. getPassword (), presentedPassword, salt) {logger. debug ("Authentication failed: password does not match stored value"); throw new BadCredentialsException ("the user name or password is incorrect! ");}}}
The supports method specifies that the custom token is used. The additionalAuthenticationChecks method has the same logic as the parent class. I just changed the information returned by the exception.
The next step is handler that handles authentication success and authentication failure.
import org.springframework.security.core.Authentication;import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;public class FrontAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { public FrontAuthenticationSuccessHandler(String defaultTargetUrl) { super(defaultTargetUrl); } @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { super.onAuthenticationSuccess(request, response, authentication); }}
import org.springframework.security.core.AuthenticationException;import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;public class FrontAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler { public FrontAuthenticationFailureHandler(String defaultFailureUrl) { super(defaultFailureUrl); } @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { super.onAuthenticationFailure(request, response, exception); }}
Finally, it is the most important security config:
import com.service.user.CustomerService;import com.web.filter.SiteMeshFilter;import com.web.mySecurity.*;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.core.annotation.Order;import org.springframework.security.authentication.AuthenticationManager;import org.springframework.security.authentication.AuthenticationProvider;import org.springframework.security.authentication.ProviderManager;import org.springframework.security.config.annotation.web.builders.HttpSecurity;import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;import org.springframework.security.crypto.password.PasswordEncoder;import org.springframework.security.crypto.password.StandardPasswordEncoder;import org.springframework.security.web.access.ExceptionTranslationFilter;import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;import org.springframework.web.filter.CharacterEncodingFilter;import javax.servlet.DispatcherType;import javax.servlet.FilterRegistration;import javax.servlet.ServletContext;import java.util.ArrayList;import java.util.EnumSet;import java.util.List;@Configuration@EnableWebSecuritypublic class SecurityConfig extends AbstractSecurityWebApplicationInitializer { @Bean public PasswordEncoder passwordEncoder() { return new StandardPasswordEncoder("MD5"); } @Autowired private CustomerService customerService; @Configuration @Order(1) public static class FrontendWebSecurityConfigureAdapter extends WebSecurityConfigurerAdapter { @Autowired private MyValidCodeProcessingFilter myValidCodeProcessingFilter; @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests() .antMatchers("/user/login", "/user/logout").permitAll() .anyRequest().authenticated() .and() .addFilterBefore(myValidCodeProcessingFilter, UsernamePasswordAuthenticationFilter.class) .formLogin() .loginPage("/user/login") .and() .logout() .logoutUrl("/user/logout") .logoutSuccessUrl("/user/login"); } } @Bean(name = "frontAuthenticationProvider") public MyAuthenticationProvider frontAuthenticationProvider() { MyAuthenticationProvider myAuthenticationProvider = new MyAuthenticationProvider(); myAuthenticationProvider.setUserDetailsService(customerService); myAuthenticationProvider.setPasswordEncoder(passwordEncoder()); return myAuthenticationProvider; } @Bean public AuthenticationManager authenticationManager() { List<AuthenticationProvider> list = new ArrayList<>(); list.add(frontAuthenticationProvider()); AuthenticationManager authenticationManager = new ProviderManager(list); return authenticationManager; } @Bean public MyValidCodeProcessingFilter myValidCodeProcessingFilter(AuthenticationManager authenticationManager) { MyValidCodeProcessingFilter filter = new MyValidCodeProcessingFilter(); filter.setAuthenticationManager(authenticationManager); filter.setAuthenticationSuccessHandler(frontAuthenticationSuccessHandler()); filter.setAuthenticationFailureHandler(frontAuthenticationFailureHandler()); return filter; } @Bean public FrontAuthenticationFailureHandler frontAuthenticationFailureHandler() { return new FrontAuthenticationFailureHandler("/user/login"); } @Bean public FrontAuthenticationSuccessHandler frontAuthenticationSuccessHandler() { return new FrontAuthenticationSuccessHandler("/front/test"); } @Bean public MyAuthenticationEntryPoint myAuthenticationEntryPoint() { return new MyAuthenticationEntryPoint("/user/login"); }}
The first is an encryption bean. customerService is a simple query user.
@Service("customerService")public class CustomerServiceImpl implements CustomerService { @Autowired private UserDao userDao; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { return userDao.findCustomerByUsername(username); }}
The FrontendWebSecurityConfigureAdapter method is used to rewrite the configure method. Disable csrf and enable the authorization request authorizeRequests (), where "/user/login" and "/user/logout" are used for permission verification, other requests require logon authentication, followed by addFilterBefore (). Before adding my custom myValidCodeProcessingFilter to the default security UsernamePasswordAuthenticationFilter, that is, first perform custom parameter authentication, then formLogin () is used to configure the logon url and logout url. controller ing is required for logon and logout URLs, that is, to write the controller by yourself.
Next we will discuss the bean display declaration of AuthenticationProvider, AuthenticationManager, ProcessingFilter, AuthenticationFailureHandler, AuthenticationSuccessHandler, and EntryPoint.
Below is login. jsp
<Body> <div class = "login_div"> <form: form autocomplete = "false" commandName = "userDTO" method = "post"> <div> <span class = "error_tips"> <B >$ {SPRING_SECURITY_LAST_EXCEPTION.message} </B> </span> </div> username: <form: input path = "username" cssClass = "form-control"/> <br/> password: <form: password path = "password" cssClass = "form-control"/> <br/> validateCode: <form: input path = "validateCode" cssClass = "form-control"/> <label >$ {validate_code} </label> <div class = "checkbox"> <label> <input type = "checkbox" name = "remember-me"/> remember me </label> </div> <input type = "submit" class = "btn-primary" value =" submit "/> </form: form> </div> </body>
When the Verification Code fails, ValidCodeErrorException is thrown. Because it inherits the AuthenticationException, security triggers the AuthenticationFailureHandler when it encounters the AuthenticationException. The bean above declares that the authentication failure jumps to the logon url, so login. in jsp, $ {SPRING_SECURITY_LAST_EXCEPTION.message} is used to obtain the exception information that is thrown during my authentication, so that users can be kindly notified.
The entire custom security verification process is complete.
The above is all the content of this article. I hope it will be helpful for your learning and support for helping customers.