Application scenarios
The existing database contains the following tables for permission management:
Springsecurity should be integrated on this basis, and table data should be used as a data source to complete the login and permission verification logic.
Springsecurity configurations can be presented in two ways: based on its own namespace configuration and traditional bean-based configuration. Using namespace to configure security is very simple, which hides a lot of complicated implementation details, but it is not easy for beginners to understand. If you want to customize Security (replacing existing functions ), it is best to use the traditional bean-based configuration method. Although the structure is complex, the details are clear and clear.
The following are two methods of configuration comparison:
1. Configure Based on namespace
<beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">
2. Restore the same configuration to Bean
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:sec="http://www.springframework.org/schema/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd"> <bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy"> <constructor-arg> <list> <sec:filter-chain pattern="/js/**" filters="none"/> <sec:filter-chain pattern="/**" filters="securityContextPersistenceFilter,authenticationFilter,exceptionTranslationFilter,filterSecurityInterceptor"/> </list> </constructor-arg> </bean> <bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor"> <property name="authenticationManager" ref="authenticationManager"/> <property name="accessDecisionManager" ref="accessDecisionManager"/> <property name="securityMetadataSource"> <sec:filter-security-metadata-source use-expressions="true"> <sec:intercept-url pattern="/peoplemanage/**" access="hasRole('admin')"/> </sec:filter-security-metadata-source> </property> </bean> <!-- exceptionTranslationFilter --> <bean id="exceptionTranslationFilter" class="org.springframework.security.web.access.ExceptionTranslationFilter"> <property name="authenticationEntryPoint" ref="authenticationEntryPoint"/> <property name="accessDeniedHandler" ref="accessDeniedHandler"/> </bean> <bean id="authenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint"> <property name="loginFormUrl" value="/login.jsp"/> </bean> <bean id="accessDeniedHandler" class="org.springframework.security.web.access.AccessDeniedHandlerImpl"> <property name="errorPage" value="/error.html"/> </bean> <!-- securityContextPersistenceFilter --> <bean id="securityContextPersistenceFilter" class="org.springframework.security.web.context.SecurityContextPersistenceFilter"/> <!-- authenticationFilter --> <bean id="authenticationFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter"> <property name="authenticationManager" ref="authenticationManager"/> <property name="filterProcessesUrl" value="/j_spring_security_check"/> </bean> <!-- Core Service --> <bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager"> <property name="providers"> <list> <ref local="daoAuthenticationProvider"/> </list> </property> </bean> <bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider"> <property name="userDetailsService" ref="inMemoryDaoImpl"/> </bean> <bean id="inMemoryDaoImpl" class="org.springframework.security.provisioning.InMemoryUserDetailsManager"> <constructor-arg name="users"> <props> <prop key="zhangsan">zhangsan,enabled</prop> <prop key="wangwu">wangwu,enabled</prop> </props> </constructor-arg> </bean> <bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased"> <property name="decisionVoters"> <list> <bean class="org.springframework.security.web.access.expression.WebExpressionVoter"></bean> </list> </property> </bean></beans>
After the bean configuration method is restored, the customization becomes clearer.
1. First, you must modify the implementation of userdetailsservice.
In the preceding demo configuration, the inmemoryuserdetailsmanager built in spring is used. The main function of this class is to load information such as zhangsan and wangwu from the configuration file to build user data sources, our user data is stored in the database, so we need to modify the implementation as follows:
1. Customize a service to implement the org. springframework. Security. Core. userdetails. userdetailsservice Interface
Public class myuserdetailsservice implements userdetailsservice {public userdetails loaduserbyusername (string username) throws usernamenotfoundexception {/*** todo loads user information from the database and encapsulates it into a userdetails object */}}
2. Replace the corresponding configuration in the demo.
<bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider"> <property name="userDetailsService" ref="myUserDetailsService"/></bean><bean id="myUserDetailsService" class="com.youcompany.MyUserDetailsService"/>
2. Modify the securitymetadatasource attribute injection method in filtersecurityinterceptor.
In the demo configuration, the securitymetadatasource attribute is configured statically. The role corresponding to each resource and resource is encapsulated in the <sec: intercept-URL> tag.
Our requirement scenario is that resource information is stored in the database, so we cannot describe it in this static way. The modification method is as follows:
1. Declare a service to implement the org. springframework. Security. Web. Access. Intercept. filterinvocationsecuritymetadatasource Interface
Public class implements filterinvocationsecuritymetadatasource {private Map <requestmatcher, collection <configattribute> requestmap; Public myfilterinvocationsecuritymetadatasource () {requestmap = new hashmap <requestmatcher, collection <configattribute> (); loadmetadatainfo (); // encapsulate the resources and role entities in the database into requestmap} private void loadmetadatainfo () {list <resource> reso Urces =... // todo obtain all resource entities in the database for (resource Res: Resources) {set <configattribute> allattributes = new hashset <configattribute> (); List <role> roles =... // todo obtains the access role for (role: Roles) {allattributes. add (New securityconfig (role. getrolename ();} requestmatcher key = new antpathrequestmatcher (res. geturl () + "/**"); requestmap. put (Key, allattributes) ;}} public collection <configattribute> getallco Nfigattributes () {set <configattribute> allattributes = new hashset <configattribute> (); List <role> roles... // todo obtains all role entities in the database for (role: Roles) {allattributes. add (New securityconfig (role. getrolename ();} return allattributes;} public collection <configattribute> getattributes (Object object) throws illegalargumentexception {httpservletrequest request = (filterinvocation) object ). getrequest (); For (map. entry <requestmatcher, collection <configattribute> entry: requestmap. entryset () {If (entry. getkey (). matches (request) {return entry. getvalue () ;}return NULL;} public Boolean supports (class <?> Clazz) {return filterinvocation. Class. isassignablefrom (clazz );}}
2. Modify the corresponding configuration in the demo.
<bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor"> <property name="authenticationManager" ref="authenticationManager"/> <property name="accessDecisionManager" ref="accessDecisionManager"/> <property name="securityMetadataSource" ref="myFilterInvocationSecurityMetadataSource"/></bean><bean id="myFilterInvocationSecurityMetadataSource" class="com.youcompany.MyFilterInvocationSecurityMetadataSource"/>
3. Modify the implementation logic of decisionvoters in accessdecisionmanager
Springsecurity uses affirmativebased for access permission control by default. This class encapsulates many accessdecisionvoter objects and determines whether to access through a voting mechanism.
Accessdecisionvoter is the or logic (as long as there is an accessdecisionvoter that judges the permission to pass, the user can access the interface ).
In the demo configuration, webexpressionvoter uses the expression-based permission authentication logic (hasrole ('admin ')), however, we need to compare the user's role with the role required to access the resource to determine whether the user has access to the interface. Therefore, we need to make the following changes:
1. Declare a service to implement the org. springframework. Security. Access. accessdecisionvoter Interface
Public class myaccessdecisionvoter implements accessdecisionvoter <Object> {public Boolean supports (configattribute attribute) {return true;} public Boolean supports (class <?> Clazz) {return true;} public int vote (authentication, object, collection <configattribute> attributes) {int result = access_denied; For (configattribute attribute: attributes) {// role for (grantedauthority authority: authentication. getauthorities () {// If (attribute. getattribute (). equals (authority. getauthority () {// determines whether the user has the corresponding role return access_granted ;}} return result ;}}
2. Modify the corresponding configuration in the demo.
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased"> <property name="decisionVoters"> <list> <bean class="com.youcompany.MyAccessDecisionVoter"></bean> </list> </property></bean>
So far, springsecurity's personalized modification has been completed. A little long. Some codes are added with todo. If you have any questions, contact me. If you need the source code, you can leave a mailbox.