该demo利用maven管理:
pom.xml如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com</groupId> <artifactId>SP</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>SP Maven Webapp</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.2.2</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.3.8.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-jpa</artifactId> <version>1.11.3.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>4.0.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>4.0.4.RELEASE</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>commons-httpclient</groupId> <artifactId>commons-httpclient</artifactId> <version>2.0.2</version> </dependency> <dependency> <groupId>net.sf.json-lib</groupId> <artifactId>json-lib</artifactId> <version>2.4</version> <classifier>jdk15</classifier> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>4.3.11.Final</version> <exclusions> <exclusion> <artifactId>xml-apis</artifactId> <groupId>xml-apis</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>4.3.11.Final</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.25</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.25</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>com.oracle</groupId> <artifactId>ojdbc6</artifactId> <version>11.2.0.4</version> </dependency> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.4</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.1</version> </dependency> <dependency> <groupId>commons-net</groupId> <artifactId>commons-net</artifactId> <version>3.6</version> </dependency> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache-web</artifactId> <version>2.0.4</version> </dependency> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache</artifactId> <version>2.8.3</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>4.3.8.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.ws</groupId> <artifactId>spring-ws-core</artifactId> <version>2.1.3.RELEASE</version> </dependency> </dependencies> <build> <finalName>SystemManage</finalName> <defaultGoal>compile</defaultGoal> <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> </resource> </resources> <plugins> <!-- 编译配置 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>${java.version}</source> <target>${java.version}</target> </configuration> </plugin> <!--Tomcat 配置--> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.1</version> <configuration> <path>/SystemManage</path> <port>8081</port> <uriEncoding>UTF-8</uriEncoding> <server>tomcat7</server> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <version>2.6</version> <configuration> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> </build> </project>
配置文件:
首先过滤出项目的登陆页,
访问该项目的用户需要有'ROLE_USER'的角色,controller中定义@RequestMapping(value = "/loginPage", method = RequestMethod.GET)的登录页。
login-processing-url必须要和登录页面中的表单提交路径相同。
authentication-success-handler-ref配置登陆成功后的处理bean
authentication-faliure-url登陆失败后的跳转页面
logout-url: 登出,必须要和登出的链接相同;
invalidate-session:是否销毁session;
登陆验证:UserDetailService和PasswordEncoder
MyUserDetailService.java
package com.yin.myproject.security.controller; import java.util.ArrayList; import java.util.List; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; public class MyUserDetailService implements UserDetailsService{ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { //权限 List<SimpleGrantedAuthority> roles = new ArrayList<SimpleGrantedAuthority>(); roles.add(new SimpleGrantedAuthority("ROLE_USER")); return new User(username,username,roles); } }
MyPasswordEncoder .java
package com.yin.myproject.security.controller; import org.springframework.security.crypto.password.PasswordEncoder; public class MyPasswordEncoder implements PasswordEncoder{ public String encode(CharSequence rawPassword) { String encPassword = rawPassword.toString(); return encPassword; } public boolean matches(CharSequence rawPassword, String encodedPassword) { return encode(rawPassword).equals(encodedPassword); } }
验证成功后,进入处理登陆成功的bean
LoginSuccessHandler.java
package com.yin.myproject.security.controller; import java.io.IOException; import java.util.Collection; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.User; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; public class LoginSuccessHandler implements AuthenticationSuccessHandler{ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { Object principal = authentication.getPrincipal(); User user = (User) principal; Collection<GrantedAuthority> authorities = user.getAuthorities(); for (GrantedAuthority authority : authorities) { if (authority.getAuthority().equals("ROLE_USER")) { HttpSession session = request.getSession(); session.setAttribute("role", "ROLE_USER"); //再将用户保存在session中 response.sendRedirect(request.getContextPath() + "/welcome"); } } } }
权限控制重点记录(见下文)。
<?xml version="1.0" encoding="UTF-8"?> <bean:beans xmlns="http://www.springframework.org/schema/security" xmlns:bean="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd"> <http pattern="/loginPage" security="none"></http> <http auto-config="true" use-expressions="true"> <intercept-url pattern="/*" access="hasRole('ROLE_USER')" /> <form-login login-page="/loginPage" login-processing-url="/login" authentication-success-handler-ref="mySuccessHandler" authentication-failure-url="/loginPage?error=error" /> <logout logout-url="/logout" logout-success-url="/loginPage" invalidate-session="true"/> <remember-me key="authorition" use-secure-cookie="true"/> <!-- 权限控制 --> <custom-filter ref="myFilter" before="FILTER_SECURITY_INTERCEPTOR"/> <csrf disabled="true" /> </http> <authentication-manager alias="authenticationManager"> <authentication-provider user-service-ref="myUserDetailService"> <!-- <user-service> --> <!-- <user authorities="ROLE_USER" name="guest" password="guest" /> --> <!-- </user-service> --> <!-- 密码加密 --> <password-encoder ref="myPasswordEncoder"/> </authentication-provider> </authentication-manager> <bean:bean id="myUserDetailService" class="com.yin.myproject.security.controller.MyUserDetailService"></bean:bean> <bean:bean id="myPasswordEncoder" class="com.yin.myproject.security.controller.MyPasswordEncoder"></bean:bean> <bean:bean id="mySuccessHandler" class="com.yin.myproject.security.controller.LoginSuccessHandler"></bean:bean> <!-- 权限控制过滤器 --> <bean:bean id="myFilter" class="com.yin.myproject.security.controller.MyfilterSecurityInterceptor"> <bean:property name="accessDecisionManager" ref="accessDecisionManager"></bean:property> <bean:property name="securityMetadataSourceService" ref="securityMetadataSourceService"></bean:property> </bean:bean> <!-- 投票规则 --> <bean:bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased"> <bean:constructor-arg name="decisionVoters"> <bean:list> <!-- <ref bean="roleVoter"/> --> <!-- <ref bean="authenticatedVoter"/> --> <bean:ref bean="defaultVoter" /> </bean:list> </bean:constructor-arg> </bean:bean> <!-- 自定义投票器 --> <bean:bean id="defaultVoter" class="com.yin.myproject.security.controller.DefaultVoter"></bean:bean> <bean:bean id="securityMetadataSourceService" class="com.yin.myproject.security.controller.MyInvocationSecurityMetadataSourceService"></bean:bean> </bean:beans>
重点记录权限配置:
配置文件中定义过滤器myfilter用来做权限,这个过滤器在spring security的FILTER_SECURITY_INTERCEPTOR之前。
MyfilterSecurityInterceptor.java
package com.yin.myproject.security.controller; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import org.springframework.security.access.SecurityMetadataSource; import org.springframework.security.access.intercept.AbstractSecurityInterceptor; import org.springframework.security.access.intercept.InterceptorStatusToken; import org.springframework.security.web.FilterInvocation; import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; public class MyfilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter{ private FilterInvocationSecurityMetadataSource securityMetadataSourceService; public void init(FilterConfig filterConfig) throws ServletException { // TODO Auto-generated method stub } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { FilterInvocation fi = new FilterInvocation(request, response, chain); invoke(fi); } public void destroy() { // TODO Auto-generated method stub } @Override public Class<?> getSecureObjectClass() { return FilterInvocation.class; } @Override public SecurityMetadataSource obtainSecurityMetadataSource() { return this.securityMetadataSourceService; } public void invoke(FilterInvocation fi) throws IOException, ServletException { //fi里面有一个被拦截的url //里面调用MyInvocationSecurityMetadataSource的getAttributes(Object object)这个方法获取fi对应的所有权限 //再调用MyAccessDecisionManager的decide方法来校验用户的权限是否足够 InterceptorStatusToken token = super.beforeInvocation(fi); try { //执行下一个拦截器 fi.getChain().doFilter(fi.getRequest(), fi.getResponse()); } finally { super.afterInvocation(token, null); } } public FilterInvocationSecurityMetadataSource getSecurityMetadataSourceService() { return securityMetadataSourceService; } public void setSecurityMetadataSourceService( FilterInvocationSecurityMetadataSource securityMetadataSourceService) { this.securityMetadataSourceService = securityMetadataSourceService; } }
在这个bean中配置属性accessDecisionManager和securityMetadataSourceService,这两个bean分别定义了权限采用的投票规则和初始化访问的链接和访问它所需要权限的对应关系。
MyInvocationSecurityMetadataSourceService.java
package com.yin.myproject.security.controller; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.springframework.beans.factory.InitializingBean; import org.springframework.security.access.ConfigAttribute; import org.springframework.security.access.SecurityConfig; import org.springframework.security.web.FilterInvocation; import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; public class MyInvocationSecurityMetadataSourceService implements FilterInvocationSecurityMetadataSource,InitializingBean{ private static Map<String, Collection<ConfigAttribute>> resourceMap = null; //初始化链接和权限的关系 private void loadResourceDefine(){ resourceMap = new HashMap<String, Collection<ConfigAttribute>>(); //得到所有权限 String tempAuth = "ROLE_USER"; List<String> auths = new ArrayList<String>(); //得到链接 List<String> urls = new ArrayList<String>(); auths.add(tempAuth); for(String auth:auths){ ConfigAttribute ca = new SecurityConfig(auth); String tempUrl = "/welcome" ; urls.add(tempUrl); for(String url:urls){ if(resourceMap.containsKey(url)){ Collection<ConfigAttribute> value = resourceMap.get(url); value.add(ca); resourceMap.put(url, value); }else{ Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>(); atts.add(ca); resourceMap.put(url, atts); } } } } public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException { String url = ((FilterInvocation) object).getRequestUrl(); int firstQuestionMarkIndex = url.indexOf("?"); if (firstQuestionMarkIndex != -1) { url = url.substring(0, firstQuestionMarkIndex); } Iterator<String> ite = resourceMap.keySet().iterator(); while (ite.hasNext()) { String resURL = ite.next(); if (url.equals(resURL)) { return resourceMap.get(resURL); } } return null; } public Collection<ConfigAttribute> getAllConfigAttributes() { return null; } public boolean supports(Class<?> clazz) { return true; } //bean加载后初始化 public void afterPropertiesSet() throws Exception { loadResourceDefine(); } }
defaultVoter是自定义的投票器。它需要添加在投票规则中。
DefaultVoter.java
package com.yin.myproject.security.controller; import java.util.Collection; import org.springframework.security.access.AccessDecisionVoter; import org.springframework.security.access.ConfigAttribute; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; public class DefaultVoter implements AccessDecisionVoter<Object>{ public boolean supports(ConfigAttribute attribute) { return true; } public boolean supports(Class<?> clazz) { return true; } public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) { int result = ACCESS_ABSTAIN; Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities(); for (ConfigAttribute attribute : attributes) { if (this.supports(attribute)) { result = ACCESS_DENIED; // Attempt to find a matching granted authority for (GrantedAuthority authority : authorities) { if (attribute.getAttribute().equals(authority.getAuthority())) { return ACCESS_GRANTED; } } } } return result; } }
代码下载:
https://i.cnblogs.com/Files.aspx中的SP.rar
下图记录一个描述spring-security的流程图: