Spring Security 從配置入門 學習講解。劊子手------------securityConfig.xml

不知道個人web.xml 你們都理解了沒。  廢話確實有點多,可能不少知識點,你們都知道,但是我學的時候,壓根什麼都不懂啊....java

這篇咱們要講劊子手  securityConfig。 爲何要說他是劊子手呢?  由於他是無良掌櫃的小工,直接的操盤手......web

<?xml version="1.0" encoding="UTF-8"?>
<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/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.0.xsd">
    <http access-denied-page = "/accessDenied.jsp">        <!-- 訪問拒絕頁面 -->
        <form-login login-page="/login.jsp"/>   <!-- 定義登錄界面 -->
        <intercept-url pattern="/login.jsp" filters="none"/>
        <session-management>
            <concurrency-control max-sessions="1" error-if-maximum-exceeded="true"/>  <!-- 用戶最大登陸數設置爲1 ,超過則引起異常 -->
        </session-management>                  
        <custom-filter ref="myFilter" before="FILTER_SECURITY_INTERCEPTOR"/>  <!-- 自定義FILTER ,FilterSecurityInterceptor 負責受權-->
    </http>
    <!-- myFilter -->
    <beans:bean id = "myFilter" class = "com.qbt.spring.security.MyFilterSecurityInterceptor">
            <beans:property name="authenticationManager" ref ="authenticationManager"></beans:property>  <!-- 登錄驗證 ,驗證你的用戶名密碼噼裏啪啦-->
            <beans:property name="securityMetadataSource" ref = "securityMetadataSource"></beans:property>  <!-- 資源數據源的定義 ,神馬權限對應神馬資源 噼裏啪啦-->
             <beans:property name="accessDecisionManager" ref="myAccessDecisionManagerBean"></beans:property>  <!-- 訪問決策 有沒有權限訪問資源 噼裏啪啦-->
    </beans:bean>                                                 
    
    <!-- 驗證配置,認證管理器,實現UserDetailService接口 -->
    <!-- authenticationManager 能夠有多個provider提供信息,咱們用myUserDetailService獲取信息 -->
    <!-- Spring Security中進行身份驗證的是AuthenticationManager接口,ProviderManager是它的一個默認實現,
        但它並不用來處理身份認證,而是委託給配置好的AuthenticationProvider,每一個AuthenticationProvider會輪流檢查身份認證。
        檢查後或者返回Authentication對象或者拋出異常 -->
    <authentication-manager alias="authenticationManager">
        <authentication-provider user-service-ref="myUserDetailService"></authentication-provider>    
    </authentication-manager>
    
    <!-- 獲取user數據,能夠從數據庫中獲取用戶密碼,角色等! -->
    <beans:bean id = "myUserDetailService" class = "com.qbt.spring.security.MyUserDetailService"></beans:bean>
    
    <!-- 訪問決策器,決定用戶的角色,訪問的權限 -->
    <beans:bean id = "myAccessDecisionManagerBean" class = "com.qbt.spring.security.MyAccessDecisionManager"></beans:bean>
    
    <!-- 資源數據源的定義 什麼資源對應什麼權限,或者什麼資源能被什麼角色訪問-->
    <beans:bean id = "securityMetadataSource" class = "com.qbt.spring.security.MyInvocationSecurityMetadataSource"></beans:bean>
    
</beans:beans>

能夠看出來,這裏的核心過濾器是咱們本身實現的MyFilterSecurityInterceptorspring

//下面,貼出他的代碼sql

package com.qbt.spring.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;

/**
 *登錄後,每次訪問資源都會訪問這個攔截器 ,執行doFilter, 調用invoke, 
 *super.beforeInvocation() 會調用SecurityMetadataSource 的getAttributes方法獲取fi對應的全部權限,再調用decide的方法,判斷是否有權限
 *而後調用下一個攔截器。
 *    
 */
public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter{
    
    //配置文件注入
    private FilterInvocationSecurityMetadataSource securityMetadataSource;
    
    //登錄後,每次訪問資源都經過這個攔截器攔截
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        FilterInvocation fi = new FilterInvocation(request, response, chain);
        invoke(fi);
    }

    private void invoke(FilterInvocation fi) throws IOException, ServletException {
        //fi 封裝了request,response,chain
        //裏面調用MyInvocationSecurityMetadataSource的getAttributes(Object object)這個方法獲取fi對應的全部權限
        //再調用MyAccessDecisionManager的decide方法來校驗用戶的權限是否足夠
        
        InterceptorStatusToken token = super.beforeInvocation(fi);
        
        //這裏的token裏面究竟是什麼呢?  八一八 來!
        /**
         * 源碼---
         *  protected InterceptorStatusToken beforeInvocation(Object object)
            {
                Assert.notNull(object, "Object was null");   //預言
                //省略
                Collection attributes = obtainSecurityMetadataSource().getAttributes(object);
                //調用MyInvocationSecurityMetadataSource的getAttributes(Object object)這個方法獲取fi對應的全部權限
                if(attributes == null)
                {
                    //拋異常省略
                    return null;
                }
                //省略
                //判斷是否須要對認證明體從新認證,默認爲否   
                Authentication authenticated = authenticateIfRequired();
                try
                {//decide方法來校驗用戶的權限是否足夠
                    accessDecisionManager.decide(authenticated, object, attributes);
                }
                catch(AccessDeniedException accessDeniedException)
                {//拋異常
                    publishEvent(new AuthorizationFailureEvent(object, attributes, authenticated, accessDeniedException));
                    throw accessDeniedException;
                }
                //省略
                return new InterceptorStatusToken(authenticated, true, attributes, object);
            }
         * 
         */
        try{
            fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
        } finally{
            super.afterInvocation(token, null);
        }
    }
    
    @Override
    public void init(FilterConfig arg0) throws ServletException {
        
    }
    //相對應的MyAccessDecisionManager的supports方法必須放回true,不然會提醒類型錯誤 
    @Override
    public Class<? extends Object> getSecureObjectClass() {
        return FilterInvocation.class;
    }

    @Override
    public SecurityMetadataSource obtainSecurityMetadataSource() {
        return this.securityMetadataSource;
    }

    public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource  newSource  ){
        this.securityMetadataSource = newSource;
    }
    
    @Override
    public void destroy() {
        
    }
}

 

 //累啊...數據庫

而後咱們來看看 authenticationManager緩存

 

package com.qbt.spring.security; import java.util.ArrayList; import java.util.Collection; import org.springframework.dao.DataAccessException; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.GrantedAuthorityImpl; 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{ /** * 獲取用戶信息,返回User放到Spring的全局緩存SecurityContentHolder中,讓其餘過濾器使用 */ @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException { UserDetails user = null; Collection<GrantedAuthority> auths=new ArrayList<GrantedAuthority>(); //定義一個權限集合 GrantedAuthorityImpl auth1 = new GrantedAuthorityImpl("ROLE_ADMIN"); //定義一個管理員權限 GrantedAuthorityImpl auth2 = new GrantedAuthorityImpl("ROLE_USER"); //定義一個用戶權限 System.out.println("**********MyUserDetailService登錄驗證,經過用戶名獲取權限************"); if(username.equals("admin")){ auths.add(auth2); auths.add(auth1); }else{ auths.add(auth2); } // username, password, enable, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities user = new User(username, "admin", true, true, true, true, auths); return user; } }

 而後再看看MyInvocationSecurityMetadataSourcetomcat

 

package com.qbt.spring.security; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; 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 org.springframework.security.web.util.AntUrlPathMatcher; import org.springframework.security.web.util.UrlMatcher; /** * @author ORC * FilterInvocationSecurityMetadataSource 繼承於 SecurityMetadataSource * */ public class MyInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource { private UrlMatcher urlMatcher = new AntUrlPathMatcher(); public static Map<String,Collection<ConfigAttribute>> resourceMap = null; public MyInvocationSecurityMetadataSource () { loadResourceDefine(); } /** * 獲取角色和資源的相對應的關係,在tomcat啓動時加載。 * 由於是在tomcat啓動時就要加載,因此若是權限對應關係改變的話,就須要從新獲取 * 若是要調用Dao的話,可是在啓動的時候,這個Dao可能尚未加載 * 因此若是要在這裏調用數據庫的話,要本身寫sessionfaction,sql/hql * 還有一種方法就是,在getAttributes方法裏調用Dao,由於這個方法是在tomcat啓動以後才調用的 */ 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 no = new SecurityConfig("ROLE_NO"); attsNo.add(no); resourceMap.put("/other.jsp", attsNo); System.out.println("*************MyInvocationSecurityMetadataSource 調用,獲取角色和資源對應值*******************"); } @Override public Collection<ConfigAttribute> getAttributes(Object obj) throws IllegalArgumentException { String url = ((FilterInvocation)obj).getRequestUrl(); System.out.println("*************MyInvocationSecurityMetadataSource getAttribute調用,獲取資源所對應的角色集合*******************"); Iterator<String>ite = resourceMap.keySet().iterator(); while(ite.hasNext()){ String resUrl = ite.next(); if(urlMatcher.pathMatchesUrl(resUrl, url)) { return resourceMap.get(resUrl); } } return null; } @Override public Collection<ConfigAttribute> getAllConfigAttributes() { return null; } @Override public boolean supports(Class<?> class1) { return true; } }

 再看MyAccessDecisionManager安全

package com.qbt.spring.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.access.SecurityConfig; import org.springframework.security.authentication.InsufficientAuthenticationException; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; public class MyAccessDecisionManager implements AccessDecisionManager{ @Override public void decide(Authentication authentication, Object obj, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException { if(configAttributes == null) { return; } System.out.println("*************MyAccessDecesionManager 判斷用戶是否有權限**************"); Iterator<ConfigAttribute> itr = configAttributes.iterator(); while(itr.hasNext()){ ConfigAttribute ca = itr.next(); String needRole = ((SecurityConfig)ca).getAttribute(); for(GrantedAuthority ga : authentication.getAuthorities()){ if(needRole.equals(ga.getAuthority())){ return; } } } throw new AccessDeniedException("No Right"); } //這個 supports(ConfigAttribute) 方法在啓動的時候被 //AbstractSecurityInterceptor調用,來決定AccessDecisionManager //是否能夠執行傳遞ConfigAttribute  @Override public boolean supports(ConfigAttribute configattribute) { return false; } //supports(Class)方法被安全攔截器實現調用, //包含安全攔截器將顯示的AccessDecisionManager支持安全對象的類型。  @Override public boolean supports(Class<?> class1) { return true; } }
相關文章
相關標籤/搜索