<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    paulwong

    Spring Security 3.x 完整入門教程(轉(zhuǎn))

    Spring Security 3.x 出來一段時(shí)間了,跟Acegi是大不同了,與2.x的版本也有一些小小的區(qū)別,網(wǎng)上有一些文檔,也有人翻譯Spring Security 3.x的guide,但通過閱讀guide,無法馬上就能很容易的實(shí)現(xiàn)一個(gè)完整的實(shí)例。

    我花了點(diǎn)兒時(shí)間,根據(jù)以前的實(shí)戰(zhàn)經(jīng)驗(yàn),整理了一份完整的入門教程,供需要的朋友們參考。
    1,建一個(gè)web project,并導(dǎo)入所有需要的lib,這步就不多講了。
    2,配置web.xml,使用Spring的機(jī)制裝載:


    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
        xmlns:xsi
    ="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation
    ="http://java.sun.com/xml/ns/j2ee 
        http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
    >
        
    <context-param>
            
    <param-name>contextConfigLocation</param-name>
            
    <param-value>classpath:applicationContext*.xml</param-value>
        
    </context-param>

        
    <listener>
            
    <listener-class>
                org.springframework.web.context.ContextLoaderListener
            
    </listener-class>
        
    </listener>

        
    <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>


        
    <welcome-file-list>
            
    <welcome-file>login.jsp</welcome-file>
        
    </welcome-file-list>
    </web-app>
    這個(gè)文件中的內(nèi)容我相信大家都很熟悉了,不再多說了。

    2,來看看applicationContext-security.xml這個(gè)配置文件,關(guān)于Spring Security的配置均在其中:


    <?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="/403.jsp"><!-- 當(dāng)訪問被拒絕時(shí),會(huì)轉(zhuǎn)到403.jsp -->
            
    <intercept-url pattern="/login.jsp" filters="none" />
            
    <form-login login-page="/login.jsp"
                authentication-failure-url
    ="/login.jsp?error=true"
                default-target-url
    ="/index.jsp" />
            
    <logout logout-success-url="/login.jsp" />
            
    <http-basic />
            
    <!-- 增加一個(gè)filter,這點(diǎn)與Acegi是不一樣的,不能修改默認(rèn)的filter了,這個(gè)filter位于FILTER_SECURITY_INTERCEPTOR之前 -->
            
    <custom-filter before="FILTER_SECURITY_INTERCEPTOR"
                ref
    ="myFilter" />
        
    </http>

        
    <!-- 一個(gè)自定義的filter,必須包含authenticationManager,accessDecisionManager,securityMetadataSource三個(gè)屬性,
        我們的所有控制將在這三個(gè)類中實(shí)現(xiàn),解釋詳見具體配置 
    -->
        
    <beans:bean id="myFilter" class="com.robin.erp.fwk.security.MyFilterSecurityInterceptor">
            
    <beans:property name="authenticationManager"
                ref
    ="authenticationManager" />
            
    <beans:property name="accessDecisionManager"
                ref
    ="myAccessDecisionManagerBean" />
            
    <beans:property name="securityMetadataSource"
                ref
    ="securityMetadataSource" />
        
    </beans:bean>
        
        
    <!-- 認(rèn)證管理器,實(shí)現(xiàn)用戶認(rèn)證的入口,主要實(shí)現(xiàn)UserDetailsService接口即可 -->
        
    <authentication-manager alias="authenticationManager">
            
    <authentication-provider
                
    user-service-ref="myUserDetailService">
                
    <!--   如果用戶的密碼采用加密的話,可以加點(diǎn)“鹽”
                    <password-encoder hash="md5" />
                
    -->
            
    </authentication-provider>
        
    </authentication-manager>
        
    <beans:bean id="myUserDetailService"
            class
    ="com.robin.erp.fwk.security.MyUserDetailService" />

        
    <!-- 訪問決策器,決定某個(gè)用戶具有的角色,是否有足夠的權(quán)限去訪問某個(gè)資源 -->
        
    <beans:bean id="myAccessDecisionManagerBean"
            class
    ="com.robin.erp.fwk.security.MyAccessDecisionManager">
        
    </beans:bean>
        
        
    <!-- 資源源數(shù)據(jù)定義,即定義某一資源可以被哪些角色訪問 -->
        
    <beans:bean id="securityMetadataSource"
            class
    ="com.robin.erp.fwk.security.MyInvocationSecurityMetadataSource" />

    </beans:beans>


    3,來看看自定義filter的實(shí)現(xiàn):


    package com.robin.erp.fwk.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 MyFilterSecurityInterceptor extends AbstractSecurityInterceptor
            
    implements Filter {

        
    private FilterInvocationSecurityMetadataSource securityMetadataSource;

        
    // ~ Methods
        
    // ========================================================================================================

        
    /** *//**
         * Method that is actually called by the filter chain. Simply delegates to
         * the {
    @link #invoke(FilterInvocation)} method.
         * 
         * 
    @param request
         *            the servlet request
         * 
    @param response
         *            the servlet response
         * 
    @param chain
         *            the filter chain
         * 
         * 
    @throws IOException
         *             if the filter chain fails
         * 
    @throws ServletException
         *             if the filter chain fails
         
    */
        
    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 {
            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;
        }

        @Override
        
    public void destroy() {
        }

        @Override
        
    public void init(FilterConfig arg0) throws ServletException {
        }

    }
    最核心的代碼就是invoke方法中的InterceptorStatusToken token = super.beforeInvocation(fi);這一句,即在執(zhí)行doFilter之前,進(jìn)行權(quán)限的檢查,而具體的實(shí)現(xiàn)已經(jīng)交給accessDecisionManager了,下文中會(huì)講述。

    4,來看看authentication-provider的實(shí)現(xiàn):


    package com.robin.erp.fwk.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 {

        @Override
        
    public UserDetails loadUserByUsername(String username)
                
    throws UsernameNotFoundException, DataAccessException {
            Collection
    <GrantedAuthority> auths=new ArrayList<GrantedAuthority>();
            GrantedAuthorityImpl auth2
    =new GrantedAuthorityImpl("ROLE_ADMIN");
            auths.add(auth2);
            
    if(username.equals("robin1")){
                auths
    =new ArrayList<GrantedAuthority>();
                GrantedAuthorityImpl auth1
    =new GrantedAuthorityImpl("ROLE_ROBIN");
                auths.add(auth1);
            }

            
    //        User(String username, String password, boolean enabled, boolean accountNonExpired,
    //                    boolean credentialsNonExpired, boolean accountNonLocked, Collection<GrantedAuthority> authorities) {
            User user = new User(username,
                    
    "robin"truetruetruetrue, auths);
            
    return user;
        }

        
    }

    在這個(gè)類中,你就可以從數(shù)據(jù)庫中讀入用戶的密碼,角色信息,是否鎖定,賬號(hào)是否過期等,我想這么簡單的代碼就不再多解釋了。

    5,對于資源的訪問權(quán)限的定義,我們通過實(shí)現(xiàn)FilterInvocationSecurityMetadataSource這個(gè)接口來初始化數(shù)據(jù)。

    package com.robin.erp.fwk.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;

    /** *//**
     * 
     * 此類在初始化時(shí),應(yīng)該取到所有資源及其對應(yīng)角色的定義
     * 
     * 
    @author Robin
     * 
     
    */
    public class MyInvocationSecurityMetadataSource
            
    implements FilterInvocationSecurityMetadataSource {
        
    private UrlMatcher urlMatcher = new AntUrlPathMatcher();;
        
    private static Map<String, Collection<ConfigAttribute>> resourceMap = null;

        
    public MyInvocationSecurityMetadataSource() {
            loadResourceDefine();
        }

        
    private void loadResourceDefine() {
            resourceMap 
    = new HashMap<String, Collection<ConfigAttribute>>();
            Collection
    <ConfigAttribute> atts = new ArrayList<ConfigAttribute>();
            ConfigAttribute ca 
    = new SecurityConfig("ROLE_ADMIN");
            atts.add(ca);
            resourceMap.put(
    "/index.jsp", atts);
            resourceMap.put(
    "/i.jap", atts);
        }

        
    // According to a URL, Find out permission configuration of this URL.
        public Collection<ConfigAttribute> getAttributes(Object object)
                
    throws IllegalArgumentException {
            
    // guess object is a URL.
            String url = ((FilterInvocation)object).getRequestUrl();
            Iterator
    <String> ite = resourceMap.keySet().iterator();
            
    while (ite.hasNext()) {
                String resURL 
    = ite.next();
                
    if (urlMatcher.pathMatchesUrl(url, resURL)) {
                    
    return resourceMap.get(resURL);
                }
            }
            
    return null;
        }

        
    public boolean supports(Class<?> clazz) {
            
    return true;
        }
        
        
    public Collection<ConfigAttribute> getAllConfigAttributes() {
            
    return null;
        }

    }
    看看loadResourceDefine方法,我在這里,假定index.jsp和i.jsp這兩個(gè)資源,需要ROLE_ADMIN角色的用戶才能訪問。
    這個(gè)類中,還有一個(gè)最核心的地方,就是提供某個(gè)資源對應(yīng)的權(quán)限定義,即getAttributes方法返回的結(jié)果。注意,我例子中使用的是AntUrlPathMatcher這個(gè)path matcher來檢查URL是否與資源定義匹配,事實(shí)上你還要用正則的方式來匹配,或者自己實(shí)現(xiàn)一個(gè)matcher。

    6,剩下的就是最終的決策了,make a decision,其實(shí)也很容易,呵呵。

    package com.robin.erp.fwk.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 {

        
    //In this method, need to compare authentication with configAttributes.
        
    // 1, A object is a URL, a filter was find permission configuration by this URL, and pass to here.
        
    // 2, Check authentication has attribute in permission configuration (configAttributes)
        
    // 3, If not match corresponding authentication, throw a AccessDeniedException.
        public void decide(Authentication authentication, Object object,
                Collection
    <ConfigAttribute> configAttributes)
                
    throws AccessDeniedException, InsufficientAuthenticationException {
            
    if(configAttributes == null){
                
    return ;
            }

            System.out.println(object.toString());  
    //object is a URL.
            Iterator<ConfigAttribute> ite=configAttributes.iterator();
            
    while(ite.hasNext()){
                ConfigAttribute ca
    =ite.next();
                String needRole
    =((SecurityConfig)ca).getAttribute();
                
    for(GrantedAuthority ga:authentication.getAuthorities()){
                    
    if(needRole.equals(ga.getAuthority())){  //ga is user's role.
                        return;
                    }

                }

            }

            
    throw new AccessDeniedException("no right");
        }


        @Override
        
    public boolean supports(ConfigAttribute attribute) {
            
    // TODO Auto-generated method stub
            return true;
        }


        @Override
        
    public boolean supports(Class<?> clazz) {
            
    return true;
        }



    }



    在這個(gè)類中,最重要的是decide方法,如果不存在對該資源的定義,直接放行;否則,如果找到正確的角色,即認(rèn)為擁有權(quán)限,并放行,否則throw new AccessDeniedException("no right");這樣,就會(huì)進(jìn)入上面提到的403.jsp頁面。

    posted on 2010-03-10 21:56 paulwong 閱讀(4464) 評(píng)論(1)  編輯  收藏 所屬分類: SPRING

    Feedback

    # re: Spring Security 3.x 完整入門教程(轉(zhuǎn)) 2016-04-21 18:54 qwe

    eqweweqw  回復(fù)  更多評(píng)論   


    主站蜘蛛池模板: 好爽好紧好大的免费视频国产| 香蕉大伊亚洲人在线观看| 一级特黄录像免费播放中文版| 免费视频淫片aa毛片| 亚洲在成人网在线看| 一区二区三区福利视频免费观看| 亚洲乱亚洲乱妇无码麻豆| 成人免费观看男女羞羞视频| 国产美女做a免费视频软件| 97se亚洲国产综合自在线| 青娱乐免费视频在线观看| 亚洲成人黄色网址| 222www免费视频| 亚洲欧洲日本国产| 最近免费最新高清中文字幕韩国| 亚洲av午夜福利精品一区| 国产成人免费AV在线播放| 国产aⅴ无码专区亚洲av| 中文日本免费高清| 久久亚洲精品视频| 国产免费一区二区三区在线观看| 亚洲高清国产拍精品26U| 中文字幕免费不卡二区| 亚洲Av综合色区无码专区桃色 | 久久久久亚洲精品天堂久久久久久| 午夜亚洲乱码伦小说区69堂| 在线观看免费国产视频| 在线观看亚洲免费| 亚洲成?v人片天堂网无码| 特级毛片免费播放| 亚洲精品国产V片在线观看| 国产99精品一区二区三区免费| 在线观看亚洲成人| baoyu116.永久免费视频| 久久亚洲国产欧洲精品一| 99久热只有精品视频免费看 | 两个人看的www免费视频中文| 亚洲AV一宅男色影视| 久久午夜羞羞影院免费观看| 亚洲性色成人av天堂| 一个人看www在线高清免费看|