Spring Security 3.1
来源:互联网 发布:app运营数据报告模板 编辑:程序博客网 时间:2024/06/06 05:18
原文地址 http://blog.csdn.net/u012367513/article/details/38866465
spring security 是现在比较流行的安全框架了,可以很容易的集成到项目中实现认证与授权的管理。本文基于spring security 3.1.3版本,主要参考了
L-二当家的的分享
LocalFilterSecurityInterceptor.java 登陆后,每次访问资源都会被这个拦截器拦截,会执行doFilter这个方法
package security;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 LocalFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter { //配置文件注入 private FilterInvocationSecurityMetadataSource securityMetadataSource; //登陆后,每次访问资源都通过这个拦截器拦截 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { FilterInvocation fi = new FilterInvocation(request, response, chain); invoke(fi); } public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() { return this.securityMetadataSource; } public Class<? extends Object> getSecureObjectClass() { return FilterInvocation.class; } public void invoke(FilterInvocation fi) throws IOException, ServletException { //fi里面有一个被拦截的url //里面调用LocalInvocationSecurityMetadataSource的getAttributes(Object object)这个方法获取fi对应的所有权限 //再调用LocalAccessDecisionManager的decide方法来校验用户的权限是否足够 InterceptorStatusToken token = super.beforeInvocation(fi); try { //执行下一个拦截器 fi.getChain().doFilter(fi.getRequest(), fi.getResponse()); } finally { super.afterInvocation(token, null); } } public SecurityMetadataSource obtainSecurityMetadataSource() { return this.securityMetadataSource; } public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource newSource) { this.securityMetadataSource = newSource; } public void destroy() { } public void init(FilterConfig arg0) throws ServletException { }}LocalInvocationSecurityMetadataSource这个用来加载资源与权限的全部对应关系的,并提供一个通过资源获取所有权限的方法
package security;import java.util.*;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;import util.AntUrlPathMatcher;import util.UrlMatcher;public class LocalInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource { private UrlMatcher urlMatcher = new AntUrlPathMatcher(); private static Map<String, Collection<ConfigAttribute>> resourceMap = null; //tomcat启动时实例化一次 public LocalInvocationSecurityMetadataSource() { loadResourceDefine(); } //tomcat开启时加载一次,加载所有url和权限(或角色)的对应关系 private void loadResourceDefine() { resourceMap = new HashMap<String, Collection<ConfigAttribute>>(); Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>(); ConfigAttribute ca = new SecurityConfig("ROLE_USER"); atts.add(ca); resourceMap.put("/index.jsp", atts); Collection<ConfigAttribute> attsno =new ArrayList<ConfigAttribute>(); ConfigAttribute cano = new SecurityConfig("ROLE_NO"); attsno.add(cano); resourceMap.put("/other.jsp", attsno); Collection<ConfigAttribute> attsadmin =new ArrayList<ConfigAttribute>(); ConfigAttribute canoadmin = new SecurityConfig("ROLE_ADMIN"); attsadmin.add(canoadmin); resourceMap.put("/admin.jsp", attsadmin); } //参数是要访问的url,返回这个url对于的所有权限(或角色) public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException { Collection<ConfigAttribute> configAttributes = new ArrayList<ConfigAttribute>(); // 将参数转为url String url = ((FilterInvocation)object).getRequestUrl(); Iterator<String>ite = resourceMap.keySet().iterator(); while (ite.hasNext()) { String resURL = ite.next(); if (urlMatcher.pathMatchesUrl(resURL, url)) { configAttributes.addAll(resourceMap.get(resURL)); } } return configAttributes.isEmpty() ? null : configAttributes; } public boolean supports(Class<?>clazz) { return true; } public Collection<ConfigAttribute> getAllConfigAttributes() { return null; }}LocalUserDetailService.java 提供通过用户名获取用户所有(包含权限)信息的接口
package security;import org.springframework.dao.DataAccessException;import org.springframework.security.core.GrantedAuthority;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;import java.util.ArrayList;import java.util.Collection;public class LocalUserDetailService implements UserDetailsService { //登陆验证时,通过username获取用户的所有权限信息, //并返回User放到spring的全局缓存SecurityContextHolder中,以供授权器使用 public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException { Collection<GrantedAuthority> auths = new ArrayList<GrantedAuthority>(); SimpleGrantedAuthority auth1=new SimpleGrantedAuthority("ROLE_ADMIN"); SimpleGrantedAuthority auth2=new SimpleGrantedAuthority("ROLE_USER"); SimpleGrantedAuthority auth3=new SimpleGrantedAuthority("ROLE_NO"); //用户名是admin是天啊及所有权限 if(username.equals("admin")){ auths.add(auth1); auths.add(auth2); auths.add(auth3); }else { //其他情况去掉admin权限 auths.add(auth2); auths.add(auth3); } //这里写死密码为admin,正常情况应该从数据库中查询 User user = new User(username, "admin", true, true, true, true, auths); return user; }}LocalAccessDecisionManager.java 判断用户是否具有访问资源的权限
package security;import java.util.Collection;import java.util.Iterator;import org.springframework.security.access.AccessDecisionManager;import org.springframework.security.access.AccessDeniedException;import org.springframework.security.access.ConfigAttribute;import org.springframework.security.authentication.InsufficientAuthenticationException;import org.springframework.security.core.Authentication;import org.springframework.security.core.GrantedAuthority;public class LocalAccessDecisionManager implements AccessDecisionManager { //检查用户是否够权限访问资源 //参数authentication是从spring的全局缓存SecurityContextHolder中拿到的,里面是用户的权限信息 //参数object是url //参数configAttributes所需的权限 public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException { if (configAttributes == null) { return; } Iterator<ConfigAttribute> ite = configAttributes.iterator(); while (ite.hasNext()) { ConfigAttribute ca = ite.next(); String needRole = ca.getAttribute(); for (GrantedAuthority ga : authentication.getAuthorities()) { if (needRole.equals(ga.getAuthority())) { return; } } } //注意:执行这里,后台是会抛异常的,但是界面会跳转到所配的access-denied-page页面 throw new AccessDeniedException("no right"); } public boolean supports(ConfigAttribute attribute) { return true; } public boolean supports(Class<?> clazz) { return true; }}AntUrlPathMatcher.java 匹配url工具类
package util;import org.springframework.util.AntPathMatcher;import org.springframework.util.PathMatcher;public class AntUrlPathMatcher implements UrlMatcher { private boolean requiresLowerCaseUrl; private PathMatcher pathMatcher; public AntUrlPathMatcher() { this(true); } public AntUrlPathMatcher(boolean requiresLowerCaseUrl) { this.requiresLowerCaseUrl = true; this.pathMatcher = new AntPathMatcher(); this.requiresLowerCaseUrl = requiresLowerCaseUrl; } public Object compile(String path) { if (this.requiresLowerCaseUrl) { return path.toLowerCase(); } return path; } public void setRequiresLowerCaseUrl(boolean requiresLowerCaseUrl){ this.requiresLowerCaseUrl = requiresLowerCaseUrl; } public boolean pathMatchesUrl(Object path, String url) { if (("/**".equals(path)) || ("**".equals(path))) { return true; } return this.pathMatcher.match((String)path, url); } public String getUniversalMatchPattern() { return"/**"; } public boolean requiresLowerCaseUrl() { return this.requiresLowerCaseUrl; } public String toString() { return super.getClass().getName() + "[requiresLowerCase='" + this.requiresLowerCaseUrl + "']"; }}UrlMatcher.java 工具接口
package util;public interface UrlMatcher{ Object compile(String paramString); boolean pathMatchesUrl(Object paramObject, String paramString); String getUniversalMatchPattern(); boolean requiresLowerCaseUrl();}securityConfig.xmlspring-security 配置文件
<?xml version="1.0" encoding="UTF-8"?><b:beans xmlns="http://www.springframework.org/schema/security" xmlns:b="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-3.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd"> <!--登录页面不过滤 --> <http pattern="/login.jsp" security="none" /> <http access-denied-page="/accessDenied.jsp"> <form-login login-page="/login.jsp" /> <!--访问/admin.jsp资源的用户必须具有ROLE_ADMIN的权限 --> <!-- <intercept-url pattern="/admin.jsp" access="ROLE_ADMIN" /> --> <!--访问/**资源的用户必须具有ROLE_USER的权限 --> <intercept-url pattern="/**" access="ROLE_USER" /> <session-management> <concurrency-control max-sessions="1" error-if-maximum-exceeded="false" /> </session-management> <!--增加一个filter,这点与 Acegi是不一样的,不能修改默认的filter了, 这个filter位于FILTER_SECURITY_INTERCEPTOR之前 --> <custom-filter ref="myFilter" before="FILTER_SECURITY_INTERCEPTOR" /> </http> <!--一个自定义的filter,必须包含 authenticationManager,accessDecisionManager,securityMetadataSource三个属性, 我们的所有控制将在这三个类中实现,解释详见具体配置 --> <b:bean id="myFilter" class="security.LocalFilterSecurityInterceptor"> <b:property name="authenticationManager" ref="authenticationManager" /> <b:property name="accessDecisionManager" ref="myAccessDecisionManagerBean" /> <b:property name="securityMetadataSource" ref="securityMetadataSource" /> </b:bean> <!--验证配置,认证管理器,实现用户认证的入口,主要实现UserDetailsService接口即可 --> <authentication-manager alias="authenticationManager"> <authentication-provider user-service-ref="myUserDetailService"> <!--如果用户的密码采用加密的话 <password-encoder hash="md5" /> --> </authentication-provider> </authentication-manager> <!--在这个类中,你就可以从数据库中读入用户的密码,角色信息,是否锁定,账号是否过期等 --> <b:bean id="myUserDetailService" class="security.LocalUserDetailService" /> <!--访问决策器,决定某个用户具有的角色,是否有足够的权限去访问某个资源 --> <b:bean id="myAccessDecisionManagerBean" class="security.LocalAccessDecisionManager"> </b:bean> <!--资源源数据定义,将所有的资源和权限对应关系建立起来,即定义某一资源可以被哪些角色访问 --> <b:bean id="securityMetadataSource" class="security.LocalInvocationSecurityMetadataSource" /></b:beans>web.xml
<?xml version="1.0" encoding="UTF-8"?><web-app version="3.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"> <!--加载Spring XML配置文件 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:securityConfig.xml</param-value> </context-param> <!-- Spring Secutiry3.1的过滤器链配置 --> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- Spring 容器启动监听器 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!--系统欢迎页面 --> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list></web-app>accessDenied.jsp 权限不足页面
<%@page pageEncoding="utf-8"%><!DOCTYPEHTMLPUBLIC"-//W3C//DTD HTML 4.01 Transitional//EN"><html><head> <title>My JSP 'accessDenied.jsp' starting page</title></head><body>accessDenied!!!</body></html>admin.jsp 管理员页面
<%@page pageEncoding="utf-8"%><!DOCTYPEHTMLPUBLIC"-//W3C//DTD HTML 4.01 Transitional//EN"><html><head> <title>My JSP 'admin.jsp' starting page</title></head><body>欢迎来到管理员页面.</body></html>index.jsp主页
<%@page pageEncoding="UTF-8"%><!DOCTYPEHTMLPUBLIC"-//W3C//DTD HTML 4.01 Transitional//EN"><html><head> <title>My JSP 'index.jsp' starting page</title></head><body><h3>这是首页</h3>欢迎<a href="admin.jsp">进入admin页面</a><a href="other.jsp">进入其它页面</a></body></html>login.jsp
<%@page pageEncoding="UTF-8"%><!DOCTYPEhtmlPUBLIC"-//W3C//DTD HTML 4.01 Transitional//EN"><html><head> <title>登录</title></head><body><form action ="j_spring_security_check" method="POST"> <table> <tr> <td>用户:</td> <td><input type ='text' name='j_username'></td> </tr> <tr> <td>密码:</td> <td><input type ='password' name='j_password'></td> </tr> <tr> <td><input name ="reset" type="reset"></td> <td><input name ="submit" type="submit"></td> </tr> </table></form></body></html>other.jsp
<%@ page pageEncoding="UTF-8"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head> <title>My JSP 'other.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"></head><body><h3>这里是Other页面</h3></body></html>pom 依赖
<properties> <spring-security.version>3.1.3.RELEASE</spring-security.version> <spring.version>4.3.10.RELEASE</spring.version> <servlet-api.version>3.0-alpha-1</servlet-api.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>${spring-security.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-taglibs</artifactId> <version>${spring-security.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>${spring-security.version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>${servlet-api.version}</version> <scope>provided</scope> </dependency> </dependencies>
阅读全文
0 0
- Spring Security 3.1
- 升级spring security到3.1
- Spring Security 3.1自定义登录
- Spring Security 3.1 登录验证
- Spring Security
- Spring Security
- spring security
- spring security
- spring security
- spring security
- spring security
- spring security
- spring security
- spring security
- spring security
- Spring Security
- spring security
- spring-security
- C/C++中const修饰符总结
- 大数据预科班11
- 测试入门之人工和自动化测试
- 018、static关键字
- Java获取资源路径(getResource)
- Spring Security 3.1
- linux man page 使用
- 15分钟成为Git专家
- hadoop2.74+zookeeper3.4.10+hbase1.2.6完全分布式搭建
- ADAS先进驾驶辅助系统(Advanced Driver Assistant System)
- 2018校园招聘科大讯飞校招笔试题
- HDU 1907 John
- 认识SQL查询
- 【ES6】async/await