• spring security学习(二)


    1、配置web.xml

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <web-app version="2.5" 
     3     xmlns="http://java.sun.com/xml/ns/javaee" 
     4     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     5     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
     6     http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
     7   <!-- applicationContext*.xml的位置 -->
     8   <context-param>
     9   <param-name>contextConfigLocation</param-name>
    10   <param-value>classpath:applicationContext*.xml</param-value>
    11   </context-param>
    12   <!-- 对spring进行监听 -->
    13   <listener>
    14   <listener-class>
    15   org.springframework.web.context.ContextLoaderListener
    16   </listener-class>
    17   </listener>
    18   <!-- springsecurity需要的filter -->
    19   <filter>
    20   <filter-name>springSecurityFilterChain</filter-name>
    21   <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    22   </filter>
    23   <filter-mapping>
    24   <filter-name>springSecurityFilterChain</filter-name>
    25   <url-pattern>/*</url-pattern>
    26   </filter-mapping>
    27 </web-app>

    2、配置applicationContext-security.xml(重要)

     1 <?xml version="1.0" encoding="UTF-8"?>  
     2 <beans xmlns="http://www.springframework.org/schema/beans"  
     3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
     4     xmlns:security="http://www.springframework.org/schema/security"  
     5     xsi:schemaLocation="http://www.springframework.org/schema/beans   
     6             http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
     7             http://www.springframework.org/schema/security   
     8             http://www.springframework.org/schema/security/spring-security-3.0.xsd"> 
     9 <security:http  auto-config="true" access-denied-page="/403.jsp">  <!-- 当访问拒绝(比如权限不够)时,会转到403.jsp -->
    10 <security:intercept-url pattern="/login.jsp" filters="none"/>
    11 <security:form-login login-page="/login.jsp" authentication-failure-url="/login?error=true" default-target-url="/index.jsp"/>
    12 <security:logout logout-success-url="/login.jsp"/>
    13 <security:http-basic/>
    14 <!-- 增加一个filter,且不能修改默认的filter了,这个filter位于FILTER_SECURITY_INTERCEPTOR之前-->
    15 <security:custom-filter before="FILTER_SECURITY_INTERCEPTOR" ref="myFilter"/>
    16 </security:http>
    17 18 <!-- 一个自定义的filter,必须包含authenticationManager,accessManager,securityMetadataSource三个属性 ,所有的控制都将在这三个类中实现--> 19 <bean id="myFilter" class="com.lwh.security.filter.MyFilterSecurityInterceptor"> 20 <property name="authenticationManager" ref="authenticationManager"/> 21 <property name="accessDecisionManager" ref="myAccessDecisionManagerBean"/> 22 <property name="securityMetadataSource" ref="securityMetadataSource"/> 23 </bean> 24 25 <!-- 认证管理器,实现用户认证的入口,主要实现UserDetailsService接口即可 --> 26 <security:authentication-manager alias="authenticationManager"> 27 <security:authentication-provider user-service-ref="myUserDetailService"> 28 <!-- <security:password-encoder hash="md5"/>--> 29 </security:authentication-provider> 30 </security:authentication-manager> 31 <bean id="myUserDetailService" class="com.lwh.secutity.service.MyUserDetailService"> 32 </bean> 33 <!-- 访问决策器,决定某个用户具有的角色是否有足够的权限去访问某个资源 --> 34 <bean id="myAccessDecisionManagerBean" class="com.lwh.secutity.service.MyAccessDecisionManager"> 35 </bean> 36 <!-- 资源源数据定义,即定义某一资源可以哪些角色访问 --> 37 <bean id="securityMetadataSource" class="com.lwh.secutity.service.MyInvocationSecurityMetadataSource"> 38 </bean> 39 </beans>

     3、自定义的filter的实现

     1 import java.io.IOException;
     2 import javax.servlet.Filter;
     3 import javax.servlet.FilterChain;
     4 import javax.servlet.FilterConfig;
     5 import javax.servlet.ServletException;
     6 import javax.servlet.ServletRequest;
     7 import javax.servlet.ServletResponse;
     8 import org.springframework.security.access.SecurityMetadataSource;
     9 import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
    10 import org.springframework.security.access.intercept.InterceptorStatusToken;
    11 import org.springframework.security.web.FilterInvocation;
    12 import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
    13 public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor
    14         implements Filter {
    15     private FilterInvocationSecurityMetadataSource securityMetadataSource;
    16     /**@param request
    17      *        the servlet request
    18      * @param response
    19      *        the servlet response
    20      * @param chain
    21      *        the filter chain
    22      * @throws IOException
    23      *         if the filter chain fails
    24      * @throws ServletException
    25      *         if the filter chain fails
    26      * 
    27      */
    28     public void doFilter(ServletRequest request, ServletResponse response,
    29             FilterChain chain) throws IOException, ServletException {
    30         FilterInvocation fi=new FilterInvocation(request, response, chain);
    31         invoke(fi);
    32 
    33     }
    34     public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
    35         return securityMetadataSource;
    36     }
    37     @Override
    38     public Class<? extends Object> getSecureObjectClass() {
    39         // TODO Auto-generated method stub
    40         return FilterInvocation.class;
    41     }
    42     public void invoke(FilterInvocation fi)throws IOException,ServletException{
    43         InterceptorStatusToken token=super.beforeInvocation(fi);
    44         try {
    45             fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
    46         } catch (Exception e) {
    47             // TODO: handle exception
    48         }finally{
    49             super.afterInvocation(token, null);
    50         }
    51     }
    52     @Override
    53     public SecurityMetadataSource obtainSecurityMetadataSource() {
    54         // TODO Auto-generated method stub
    55         return this.securityMetadataSource;
    56     }
    57     public void setSecurityMetadataSource(
    58             FilterInvocationSecurityMetadataSource securityMetadataSource) {
    59         this.securityMetadataSource = securityMetadataSource;
    60     }
    61     public void destroy() {
    62         // TODO Auto-generated method stub
    63 
    64     }
    65     public void init(FilterConfig arg0) throws ServletException {
    66         // TODO Auto-generated method stub
    67 
    68     }
    69 
    70 }

    最核心的代码就是invoke方法中的InterceptorStatusToken token=super.beforeInvocation(fi);这一句,即在执行doFilter之前,进行权限的检查,而具体的实现已经交给accessDecisionManager了

    4、authentication-provider的实现

     1 import java.util.ArrayList;
     2 import java.util.Collection;
     3 
     4 import org.springframework.dao.DataAccessException;
     5 import org.springframework.security.core.GrantedAuthority;
     6 import org.springframework.security.core.authority.GrantedAuthorityImpl;
     7 import org.springframework.security.core.userdetails.UserDetails;
     8 import org.springframework.security.core.userdetails.User;
     9 import org.springframework.security.core.userdetails.UserDetailsService;
    10 import org.springframework.security.core.userdetails.UsernameNotFoundException;
    11 //该类是用于从数据库中读入用户的密码、角色信息、是否锁定、账号是否过期等
    12 public class MyUserDetailService implements UserDetailsService {
    13     public UserDetails loadUserByUsername(String username)
    14             throws UsernameNotFoundException, DataAccessException {
    15         Collection<GrantedAuthority> auths=new ArrayList<GrantedAuthority>();
    16         GrantedAuthorityImpl auth2=new GrantedAuthorityImpl("ROLE_ADMIN");
    17         auths.add(auth2);
    18         if(username.equals("louis"))
    19         {
    20             auths=new ArrayList<GrantedAuthority>();
    21             GrantedAuthorityImpl auth1=new GrantedAuthorityImpl("ROLE_ROBIN");
    22             auths.add(auth1);
    23         }
    24         User user=new User(username,"louis",true,true,true,true,auths);
    25         return user;
    26          }
    27 }

    这个类中,可以从数据库中读入用户的密码,角色信息,是否锁定,账号是否过期等

    5、对于资源的访问权限定义,我们通过实现FilterInvocationSecutiryMetadataSource这个接口来初始化数据

     1 import java.util.ArrayList;
     2 import java.util.Collection;
     3 import java.util.HashMap;
     4 import java.util.Iterator;
     5 import java.util.Map;
     6 
     7 import org.springframework.security.access.ConfigAttribute;
     8 import org.springframework.security.access.SecurityConfig;
     9 import org.springframework.security.web.FilterInvocation;
    10 import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
    11 import org.springframework.security.web.util.AntUrlPathMatcher;
    12 import org.springframework.security.web.util.UrlMatcher;
    13 
    14 import com.sun.org.apache.bcel.internal.generic.NEW;
    15 //对于资源的访问权限的定义,通过FilterInvocationSecurityMetadataSource这个接口来初始化数据
    16 //假定index.jsp和i.jsp这两个页面需要Role_ADMIN角色的用户才能访问
    17 //核心的地方就是提供某个资源对应的权限定义,即getAttributes方法返回的结果
    18 //使用AntUrlPathMatcher这个pathmatcher来检查URL是否与资源定义匹配,也可以用正则表达式,或者实现自己在的一个matcher
    19 public class MyInvocationSecurityMetadataSource implements
    20         FilterInvocationSecurityMetadataSource {
    21 /**
    22  * 此类在初始化时,应该取得所有资源及其对应角色的定义
    23  */
    24     private UrlMatcher urlMatcher=new AntUrlPathMatcher();
    25     private static Map<String,Collection<ConfigAttribute>> resouMap=null;
    26     public MyInvocationSecurityMetadataSource(){
    27         loadResourceDefine();
    28     }
    29     private void loadResourceDefine()
    30     {
    31         resouMap=new HashMap<String, Collection<ConfigAttribute>>();
    32         Collection<ConfigAttribute> atts=new ArrayList<ConfigAttribute>();
    33         ConfigAttribute ca=new SecurityConfig("ROLE_ADMIN");
    34         atts.add(ca);
    35         resouMap.put("/index.jsp", atts);
    36         resouMap.put("/info.jsp", atts);
    37     }
    38     //According to a URL,find out permission configuration of this URL
    39     public Collection<ConfigAttribute> getAttributes(Object object)
    40             throws IllegalArgumentException {
    41         //guess object is a URL
    42         String url=((FilterInvocation)object).getRequestUrl();
    43         Iterator<String> iterator=resouMap.keySet().iterator();
    44         while(iterator.hasNext())
    45         {
    46             String resURL=iterator.next();
    47             if(urlMatcher.pathMatchesUrl(resURL,url)){
    48                 return resouMap.get(resURL);
    49             }
    50         }
    51         return null;
    52     }
    53     public Collection<ConfigAttribute> getAllConfigAttributes() {
    54         // TODO Auto-generated method stub
    55         return null;
    56     }
    57 
    58     public boolean supports(Class<?> clazz) {
    59         // TODO Auto-generated method stub
    60         return true;
    61     }
    62 
    63 }

    loadResourceDefine方法,假定index.jsp和info.jsp这两个资源需要ROLE_ADMIN角色的用户才能访问。

    这个类中,还有一个最核心的地方,就是提供某个资源对应的权限定义,即getAttributes方法返回的结果。

    注意:例子中使用的 AntUrlPathMatcher这个path matcher来检查URL是否与资源定义匹配,事实上还要用正则表达式匹配或者自己实现一个matcher

    6、最后的决策

     1 import java.util.Collection;
     2 import java.util.Iterator;
     3 
     4 import org.springframework.security.access.AccessDecisionManager;
     5 import org.springframework.security.access.AccessDeniedException;
     6 import org.springframework.security.access.ConfigAttribute;
     7 import org.springframework.security.access.SecurityConfig;
     8 import org.springframework.security.authentication.InsufficientAuthenticationException;
     9 import org.springframework.security.core.Authentication;
    10 import org.springframework.security.core.GrantedAuthority;
    11 //最终的决策
    12 //In this method,need to compare authentication with configAttributes.
    13 //1、A object is a URL, a filter finds permisssion configuration by this URL,and pass to here
    14 //2、Check authentication has attribute in permission configuration(configAttributes)
    15 //3、If not match corresponding authentication,throw a AccessDeniedException
    16 //这个类中最重要的是decide方法,如果不存在对该资源的定义,直接放行,否则,如果找到正确的角色,即认为拥有权限,否则抛出异常,这样就会进入403页面
    17 public class MyAccessDecisionManager implements AccessDecisionManager {
    18 
    19     public void decide(Authentication authentication, Object object,
    20             Collection<ConfigAttribute> configAttributes) throws AccessDeniedException,
    21             InsufficientAuthenticationException {
    22         if(configAttributes==null)
    23         {
    24             return;
    25         }
    26         System.out.println(object.toString());//object is a URL
    27         Iterator<ConfigAttribute> iterator=configAttributes.iterator();
    28         while(iterator.hasNext())
    29         {
    30             ConfigAttribute ca=iterator.next();
    31             String needRoleString=((SecurityConfig)ca).getAttribute();
    32             for(GrantedAuthority ga:authentication.getAuthorities())
    33             {
    34                 if(needRoleString.equals(ga.getAuthority()))
    35                 {
    36                     //ga is user's role
    37                     return;
    38                 }
    39             }
    40         }
    41         throw new AccessDeniedException("you have no right");
    42 
    43     }
    44 
    45     public boolean supports(ConfigAttribute attribute) {
    46         // TODO Auto-generated method stub
    47         return true;
    48     }
    49 
    50     public boolean supports(Class<?> clazz) {
    51         // TODO Auto-generated method stub
    52         return true;
    53     }
    54 
    55 }

    这个类中最重要的是decide方法,如果不存在对该资源的定义,直接放行;否则,如果找到正确的角色,即认为拥有权限,并放行,否则

      throw new AccessDeniedException("you have no right");即会进入403.jsp页面。
  • 相关阅读:
    python学习笔记二
    计网第三章
    python学习笔记一
    Java基础第二十七天总结——网络编程
    Java基础第二十六天总结——IO流
    Java基础第二十五天总结——泛型
    Java基础第二十四天总结——集合
    Java基础第二十三天总结——集合
    Java基础第二十二天总结——枚举类与注解
    Java基础第二十一天总结——日期时间API
  • 原文地址:https://www.cnblogs.com/wenhulu/p/5530067.html
Copyright © 2020-2023  润新知