The implementation methods of spring security can be roughly divided into these types:
1. Configuration file implementation, you only need to specify the required permissions for the intercepted url in the configuration file, configure userDetailsService to specify the username, password, and corresponding permissions, and then you can achieve it.
2. Implement the UserDetailsService, loadUserByUsername(String userName) method, and implement its own business logic based on userName to return the implementation class of UserDetails. You need to customize the User class to implement UserDetails. The more important method is getAuthorities(), which is used to return the permissions owned by the user.
3. Rewrite the spring security interceptor through custom filter to achieve dynamic filtering of user permissions.
4. Rewrite the spring security interceptor through a custom filter, implement custom parameters to verify users and filter permissions.
1. The simplest configuration, implement 1
<beans xmlns="/schema/beans" xmlns:security="/schema/security" xmlns:p="/schema/p" xmlns:xsi="http:///2001/XMLSchema-instance" xsi:schemaLocation="/schema/beans /schema/beans/spring-beans-4. /schema/security /schema/security/spring-security-4."> <!-- use-expressions:Spring Expression language configuration access control --> <security:http auto-config="true" use-expressions="false"> <!-- Configure permission blocking,Visit allurl,User login is required,And haveROLE_USERPermissions --> <security:intercept-url pattern="/**" access="ROLE_USER" /> </security:http> <security:authentication-manager alias="authenticationManager"> <security:authentication-provider> <!-- Configure the default user,username:admin password:123456 拥有Permissions:ROLE_USER --> <security:user-service> <security:user name="admin" password="123456" authorities="ROLE_USER" /> </security:user-service> </security:authentication-provider> </security:authentication-manager> </beans>
2. Implement UserDetailsService
First organize the spring security verification process:
SpringSecurity login verification is done by this filter. There is an AuthenticationManager interface property in the parent class AbstractAuthenticationProcessingFilter. The verification work is mainly done through an instance of this AuthenticationManager interface. By default, the springSecurity framework injects an instance of the class into the property
The verification process of UsernamePasswordAuthenticationFilter is as follows:
1. First, the filter will call its own attemptAuthentication method and take out authentication from the request. authentication is an interface instance generated in the filter by capturing the content in the login form submitted by the user.
2. After obtaining the authentication object, the filter will call the authentication method of the ProviderManager class and pass it in the object.
The authenticate method of the class will be called to the authentication (Authentication authentication) method in the List<AuthenticationProvider> providers set in the class for verification. It can be seen that the real verification logic is completed by the implementation classes of each AuthenticationProvider interface. DaoAuthenticationProvider class is an AuthenticationProvider interface implementation class injected by default.
When verifying the user, the implementation class of userDetailsService will call the loadUserByUsername method of the implementation class to obtain user information.
First of all, spring-security configuration file
<?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns="/schema/security" xmlns:beans="/schema/beans" xmlns:xsi="http:///2001/XMLSchema-instance" xsi:schemaLocation="/schema/beans /schema/beans/spring-beans-4. /schema/security /schema/security/"> <!-- use-expressions=”true” Need to use expressions to write permissions--> <http auto-config="true" use-expressions="false"> <!--This isspring Providedhttp/httpsChannel security is important!Your request channel is secure!--> <!-- Release user loginpage Allow anyone to access this page ,IS_AUTHENTICATED_ANONYMOUSLYIndicates no interception Another configuration that does not intercept resources:<http pattern="/" security="none"> --> <intercept-url pattern="/*" access="IS_AUTHENTICATED_ANONYMOUSLY"/> <!-- Configure user access normallypage--> <intercept-url pattern="/**" access="ROLE_USER"/> <!-- Customize user loginpage default-target-urlLogin successfully jumpedpage ,authentication-failure-url="/?error=true"Here is a jump to login failedpage--> <form-login login-page="/" default-target-url="/jsp/index/" authentication-failure-url="/?error=true"/> <!-- Remember the password --> <!-- <remember-me key="elim" user-service-ref="securityManager"/> --> </http> <authentication-manager alias="authenticationManager"> <!-- authentication-provider QuoteUserDetailsServiceUsed when implementing classesuser-service-refproperty,QuoteauthenticationWhen implementing the class,userefproperty 这两个propertyof区别在于 ref:DirectlyrefDepend onbeanInject toAuthenticationProviderofprovidersIn the collection user-service-ref:definitionDaoAuthenticationProviderofbeanInject toAuthenticationProviderofprovidersIn the collection, andDaoAuthenticationProviderof变量userDetailsServiceDepend onuser-service-refDepend onbeaninjection。 --> <authentication-provider user-service-ref="msecurityManager"> <!-- Password encryption --> <password-encoder ref="myPasswordEncoder"/> </authentication-provider> </authentication-manager> <!-- accomplishUserDetailsService --> <beans:bean class=""></beans:bean> <!-- Password encryption --> <beans:bean class=""/> </beans:beans>
userDetailsService implementation:
/** * */ package ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; public class SecurityManagerSupport implements UserDetailsService{ private Log log = (().getName()); public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException, DataAccessException { // List<User> users = getHibernateTemplate().find("FROM User user WHERE = ? AND = false", userName); (":"+userName); User user =null; if("admin".equals(userName)){ Set<Role> roles = new HashSet<Role>() ; Role role = new Role(); ("ROLE_USER"); ("ROLE_USER"); Set<Resource> resources=new HashSet<Resource>() ; Resource res = new Resource(); ("ME001"); ("front page"); ("/jsp/index/"); ("ROLE_USER"); (roles); (res); (resources); (role); user = new User(); ("admin"); (false); (()); (()); (roles); } return user;//Return UserDetails implementation user is not empty, then the verification is passed } }
UserDetails implementation:
/** * */ package ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; public class User implements UserDetails { private static final long serialVersionUID = 8026813053768023527L; private String account; private String name; private String password; private boolean disabled; private Set<Role> roles; private Map<String, List<Resource>> roleResources; /** * The default constructor */ public User() { } /** * Returns the authorites string * * eg. * downpour --- ROLE_ADMIN,ROLE_USER * robbin --- ROLE_ADMIN * * @return */ public String getAuthoritiesString() { List<String> authorities = new ArrayList<String>(); for(GrantedAuthority authority : ()) { (()); } return (authorities, ","); } @Override public Collection<? extends GrantedAuthority> getAuthorities() { // Return user permissions according to custom logic. If the user permission returns empty or the corresponding permissions are different from the intercept path, the verification will not be passed if(!()){ List<GrantedAuthority> list = new ArrayList<GrantedAuthority>(); GrantedAuthority au = new SimpleGrantedAuthority("ROLE_USER"); (au); return list; } return null; } /* * password */ public String getPassword() { return password; } /* * username */ public String getUsername() { return name; } /* * Whether the account is expired, false will not pass */ public boolean isAccountNonExpired() { return true; } /* * Whether the account is not locked, false will not pass */ public boolean isAccountNonLocked() { return true; } /* * Whether the voucher expires, false will fail to pass */ public boolean isCredentialsNonExpired() { return true; } /* * Whether this account is enabled, false will not pass */ public boolean isEnabled() { return !disabled; } /** * @return the name */ public String getName() { return name; } /** * @return the disabled */ public boolean isDisabled() { return disabled; } /** * @return the roles */ public Set<Role> getRoles() { return roles; } /** * @return the roleResources */ public Map<String, List<Resource>> getRoleResources() { // init roleResources for the first time ("---------------------------------------------------"); if( == null) { = new HashMap<String, List<Resource>>(); for(Role role : ) { String roleName = (); Set<Resource> resources = (); for(Resource resource : resources) { String key = roleName + "_" + (); if(!(key)) { (key, new ArrayList<Resource>()); } (key).add(resource); } } } return ; } /** * @param name the name to set */ public void setName(String name) { = name; } /** * @param password the password to set */ public void setPassword(String password) { = password; } /** * @param disabled the disabled to set */ public void setDisabled(boolean disabled) { = disabled; } /** * @param roles the roles to set */ public void setRoles(Set<Role> roles) { = roles; } public String getAccount() { return account; } public void setAccount(String account) { = account; } public void setRoleResources(Map<String, List<Resource>> roleResources) { = roleResources; } }
3. Implement dynamic filtering of user permissions
Add the following configuration in the http tag of the spring-security configuration file
<custom-filter before="FILTER_SECURITY_INTERCEPTOR" ref="securityInterceptor"/>
Add the following configuration in the spring-security configuration file
<!-- Custom interceptor --> <beans:bean class=""> <beans:property name="authenticationManager" ref="authenticationManager"/> <beans:property name="accessDecisionManager" ref="mesecurityAccessDecisionManager"/> <beans:property name="securityMetadataSource" ref="secureResourceFilterInvocationDefinitionSource" /> </beans:bean> <!-- Get accessurlAll corresponding permissions --> <beans:bean class="" /> <!-- Verify that the user's permissions are sufficient --> <beans:bean class="" />
securityInterceptor inherits AbstractSecurityInterceptor filter and implements Filter filter
package ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; public class SecurityInterceptor extends AbstractSecurityInterceptor implements Filter{ //Configuration file injection private FilterInvocationSecurityMetadataSource securityMetadataSource; public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() { return securityMetadataSource; } public void setSecurityMetadataSource( FilterInvocationSecurityMetadataSource securityMetadataSource) { = securityMetadataSource; } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // TODO Auto-generated method stub\ FilterInvocation fi = new FilterInvocation(request, response, chain); //There is an intercepted url in the fi //Call the getAttributes(Object object) method of MyInvocationSecurityMetadataSource to get all permissions corresponding to fi //Call the decision method of MyAccessDecisionManager to verify whether the user's permissions are sufficient InterceptorStatusToken token = (fi); try { //Execute the next interceptor ().doFilter((), ()); } finally { (token, null); } } @Override public void init(FilterConfig arg0) throws ServletException { // TODO Auto-generated method stub } @Override public Class<?> getSecureObjectClass() { // TODO Auto-generated method stub return ; } @Override public SecurityMetadataSource obtainSecurityMetadataSource() { // TODO Auto-generated method stub return ; } @Override public void destroy() { // TODO Auto-generated method stub } }
After logging in, every time you access the resource, it will be intercepted by this interceptor. The doFilter method will be executed. This method calls the invoke method, where the fi breakpoint is displayed as a url (the toString method may be rewritten, but there are some methods in it). The most important thing is the beforeInvocation method. It first calls the getAttributes method of the MyInvocationSecurityMetadataSource class to obtain the permissions required for the intercepted url, and then calls the MyAccessDecisionManager class decide method to determine whether the user has enough permissions. After all this, the next interceptor will be executed.
secureResourceFilterInvocationDefinitionSource implementation
/** * */ package ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; public class SecureResourceFilterInvocationDefinitionSource implements FilterInvocationSecurityMetadataSource, InitializingBean { private PathMatcher matcher; private static Map<String, Collection<ConfigAttribute>> map = new HashMap<String, Collection<ConfigAttribute>>(); /* * Initialize user permissions, for easy operation, no access from the database * In actual operation, you can obtain the permissions corresponding to all resource path urls from the database. */ public void afterPropertiesSet() throws Exception { = new AntPathMatcher();// Used to match the access resource path Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>(); ConfigAttribute ca = new SecurityConfig("ROLE_USER"); (ca); ("/jsp/index/", atts); Collection<ConfigAttribute> attsno =new ArrayList<ConfigAttribute>(); ConfigAttribute cano = new SecurityConfig("ROLE_NO"); (cano); ("//u012367513/article/details/", attsno); } @Override public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException { // TODO Auto-generated method stub FilterInvocation filterInvocation = (FilterInvocation) object; String requestURI = (); //Recycle resource path, when the accessed URL matches the resource path url, return the permissions required for the URL. for(Iterator<<String, Collection<ConfigAttribute>>> iter = ().iterator(); ();) { <String, Collection<ConfigAttribute>> entry = (); String url = (); if((url, requestURI)) { return (requestURI); } } return null; } @Override public Collection<ConfigAttribute> getAllConfigAttributes() { // TODO Auto-generated method stub return null; } /* (non-Javadoc) * @see #getConfigAttributeDefinitions() */ @SuppressWarnings("rawtypes") public Collection getConfigAttributeDefinitions() { return null; } /* (non-Javadoc) * @see #supports() */ public boolean supports(@SuppressWarnings("rawtypes") Class clazz) { return true; } /** * * @param filterInvocation * @return */ @SuppressWarnings("unchecked") private Map<String, String> getUrlAuthorities( filterInvocation) { ServletContext servletContext = ().getSession().getServletContext(); return (Map<String, String>)("urlAuthorities"); } }
mesecurityAccessDecisionManager implementation
package ; import ; import ; import ; import ; import ; import ; import ; import ; import ; public class SecurityAccessDecisionManager implements AccessDecisionManager { /** * Check whether the user has enough permission to access the resource * authentication is obtained from spring's global cache SecurityContextHolder, which contains user's permission information * object is url * configAttributes required permissions * @see #decide(, , ) */ @Override public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException { // When the corresponding url does not have permission, the method will be directly jumped out if(configAttributes == null){ return; } Iterator<ConfigAttribute> ite=(); //Judge whether the permissions owned by the user comply with the corresponding Url permissions. If UserDetailsService is implemented, the user permission is loadUserByUsername to return the corresponding permissions of the user. while(()){ ConfigAttribute ca=(); String needRole=((SecurityConfig)ca).getAttribute(); for(GrantedAuthority ga : ()){ (":::::::::::::"+()); if((())){ return; } } } //Note: After executing here, the background will throw exceptions, but the interface will jump to the configured access-denied-page page throw new AccessDeniedException("no right"); } @Override public boolean supports(ConfigAttribute attribute) { return true; } @Override public boolean supports(Class<?> clazz) { return true; } }
4. Implement AuthenticationProvider and customize parameter verification
This kind of verification was used in the past project, but now I have not written the sample code. I will write down the general process and the required classes.
The benefits of this verification: You can add parameters required when logging in in the custom login interface, such as multiple verification codes, etc., and you can modify the default login name and password parameter name
Overall process:
1. When the user logs in, first pass the customized passcard_filter filter, which inherits the AbstractAuthenticationProcessingFilter and binds the processor required when the login fails and succeeds (used by jumping to the page)
2. Execute the attemptAuthentication method, you can obtain the parameters passed by the login page through request, implement your own logic, and set the corresponding parameters into the implementation class of AbstractAuthenticationToken.
3. After the verification logic is completed, call the ().authenticate(token); method and execute the support method of the implementation class of AuthenticationProvider
4. If true is returned, continue to execute the authenticate method
5. In the authenticate method, first you can obtain user information based on the user name, and then you can use custom parameters and user information for logical verification, such as password verification.
6. After the custom verification is passed, obtain user permission set to User, and use it for springSecurity for permission verification.
After the ().authenticate(token) method is executed, Authentication will be returned. If it is not empty, it means that the verification has been passed
8. After verification is passed, custom logical operations can be implemented, such as recording cookie information.
After the method is executed, springSecuriy will perform corresponding permission verification, and it will be successful if it will jump to the interface set by the corresponding processor.
1. Customize the PassCardAuthenticationToken class, inherit the AbstractAuthenticationToken class, and use it to define parameters, and the methods that need to be implemented.
/** * Credentials, user password */ @Override public Object getCredentials() { return password; } /** *Party, login name User ID */ @Override public Object getPrincipal() { return userID; }
The methods that need to be implemented in class to implement Authentication
/** * Return to user's permissions */ @Override public Collection<GrantedAuthority> getAuthorities() { return ; } @Override public Object getCredentials() { return null; } @Override public Object getDetails() { return null; } /** * Login name */ @Override public Object getPrincipal() { return loginName; } /** * Certification or not */ @Override public boolean isAuthenticated() { return ; } /** * Set the authentication field */ @Override public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException { =isAuthenticated; }
3. UserService needs to implement the authentication (Authentication authentication) method of AuthenticationProvider
@SuppressWarnings("unchecked") @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { PassCardAuthenticationToken token=(PassCardAuthenticationToken)authentication; /* * Here you perform logical authentication operations, you can obtain the attributes in the token to customize the verification logic, and you can ignore the code verification logic. * If you use the UserDetailsService implementation class to verify, you can only get userName, which is not flexible enough */ if(()!=null&&()!=null){ User user=(User)().executeQueryUnique("", QueryCmdType.QUERY_NAME, ()); String password=(); if(!=null){ password=(password, null); } if(!(())){ ("2"); return null; } if( () && usePassCard ){// Activate the password card in token and the system uses the password card int position1=((token.getRow1()-1)*7)+token.getColumn1(); int position2=((token.getRow2()-1)*7)+token.getColumn2(); //( "---pos:"+position1+"---"+position2 ); if(()==null){ ("10"); return null; } PassCard passcard=((), false); if(passcard==null||()==PassCardHelper.STATUS_CANCEL ){ ("10"); return null; } if(()==null || ().length()<7*7*32 ){ ("10"); return null; } String content=(); int perLen=()/49; String str1=((position1-1)*perLen, position1*perLen); String str2=((position2-1)*perLen, position2*perLen); String inputStr1=token.getCard1(); String inputStr2=token.getCard2(); if(!=null){ inputStr1 = md5.getMD5ofStr(md5.getMD5ofStr(inputStr1)); inputStr2 = md5.getMD5ofStr(md5.getMD5ofStr(inputStr2)); } if((!(inputStr1))||(!(inputStr2))){ ("10"); return null; } } (()); (new Date()); ().saveOrUpdate(user); (true); /* * Import role permissions once, and set the permissions to User, used to spring verification of user permissions (getAuthorities method) */ List<UserRole> userRoles=(List<UserRole>)().executeQueryList("", QueryCmdType.QUERY_NAME, -1, -1, ()); Set<GrantedAuthority> accesses=new HashSet<GrantedAuthority>(); for(UserRole ur:userRoles){ (()); } ().getOrgName(); if(().getCertTypes()!=null) ().getCertTypes().size();//Delay loading (accesses); return user; } return null; }
Rewrite the supports(Class<? extends Object> authentication) method, the authentication must
/** * If the verification here fails, the authentication method will not be executed. */ @Override public boolean supports(Class<? extends Object> authentication) { return (); }
4. Define filter, implement the attemptAuthentication method of AbstractAuthenticationProcessingFilter, which is used to obtain the parameters passed on the login page. Spring only obtains userName(j_username) and password(j_username) by default, and only passes username when implementing UserDetailsService.
import ; import ; import ; import ; import ; import ; import ; import .; import ; import ; import ; import ; import ; import ; import ; import ; import ; public class PasscardAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter { private String successPage = "/home/admin/index"; private String failurePage = "/public/adminLoginEntry"; private boolean forward = false; private boolean useVerifyCode=true; private String certLoginUrl; static Logger logger = (); private WebApplicationConfiguration config; private UserLogService userLogService; public void setConfig(WebApplicationConfiguration config) { = config; } /** * Implementing parameterized structure of AbstractAuthenticationProcessingFilter * If you remember correctly, it is equivalent to the access path of the filter */ protected PasscardAuthenticationProcessingFilter() { super("/adminLoginCheck"); } public void setUseVerifyCode(boolean useVerifyCode) { = useVerifyCode; } public void setUserLogService(UserLogService userLogService) { = userLogService; } public boolean validate(HttpServletRequest request) { String userId = ("username"); String md2 = ("m"); String l = ("l"); if (userId == null || md2 == null || l == null) { return false; } long longTime = (l); if (longTime < new Date().getTime()) { return false; } try { String md1 = RemoteDataValidator.genExamMd5Digest(userId, longTime); if ((md2)) return true; } catch (Exception e) { //(); } return false; } /** * You can obtain the parameters passed by the page through request and set them to the corresponding token. */ @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException { // ("-------------------------------------------------------------------------); HttpSession s = (true); PassCardAuthenticationToken token = new PassCardAuthenticationToken(); String verifyCode = ("verifyCode"); String userID = ("username"); //....The logic of obtaining parameters and verifying and assignment is omitted here. Authentication auth = null; try { // Here we call the authenticate method of getAuthenticationManager. When the supports method returns true, the authenticate method is executed. auth = ().authenticate(token); //This is the corresponding processing logic after login is successful if (auth == null || !()) { ("__login_error", ()); } else { ("__login_error"); ("__login_username"); ("__cert_userid"); if( ()) { ("__passcard_row1"); ("__passcard_row2"); ("__passcard_column1"); ("__passcard_column2"); } } } catch (AuthenticationException e) { ("__login_error", ()); throw e; } return auth; } public void setSuccessPage(String successPage) { = successPage; } public void setFailurePage(String failurePage) { = failurePage; } public void setForward(boolean forward) { = forward; } public void setCertLoginUrl(String certLoginUrl) { = certLoginUrl; } @Override public void afterPropertiesSet() { (); /* *This processor implements AuthenticationSuccessHandler, AuthenticationFailureHandler * The interface used to handle the jump after successful or failed login */ AuthenticationResultHandler handler = new AuthenticationResultHandler(); (forward); (failurePage); (successPage); (certLoginUrl); //Set the processor in the parent class (handler); (handler); } }
Finally, for the configuration in the spring-security configuration file, you need to add a reference to authentication-provider and filter configuration.
<security:authentication-manager alias="authenticationManager"> <!-- Notice,This is just the default authentication mechanism of the system,Please clearly know its function in the official system before using it --> <security:authentication-provider ref="acocunt_defaultAnthentiactionProvider"/> <security:authentication-provider ref="registrationService"/> <security:authentication-provider ref="enrollmentService"/> <security:authentication-provider ref="userService"/> </security:authentication-manager> <bean class=""> <property name="authenticationManager" ref="authenticationManager"/> <property name="useVerifyCode" value="true"/> <property name="failurePage" value="/portal/home/auth/"></property> <property name="config" ref="webAppConfig"/> <property name="userLogService" ref="userLogService" /> <property name="certLoginUrl" value="${}"/> </bean>
Also add <security:custom-filter ref="passcard_filter" after="SECURITY_CONTEXT_FILTER"/> in http
This is the end of this article about the detailed explanation of the four implementation methods of spring security. For more related contents of spring security implementation methods, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!