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>











原创粉丝点击