<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 完整入門教程(轉)

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

    我花了點兒時間,根據以前的實戰經驗,整理了一份完整的入門教程,供需要的朋友們參考。
    1,建一個web project,并導入所有需要的lib,這步就不多講了。
    2,配置web.xml,使用Spring的機制裝載:


    <?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>
    這個文件中的內容我相信大家都很熟悉了,不再多說了。

    2,來看看applicationContext-security.xml這個配置文件,關于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"><!-- 當訪問被拒絕時,會轉到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 />
            
    <!-- 增加一個filter,這點與Acegi是不一樣的,不能修改默認的filter了,這個filter位于FILTER_SECURITY_INTERCEPTOR之前 -->
            
    <custom-filter before="FILTER_SECURITY_INTERCEPTOR"
                ref
    ="myFilter" />
        
    </http>

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

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

    </beans:beans>


    3,來看看自定義filter的實現:


    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);這一句,即在執行doFilter之前,進行權限的檢查,而具體的實現已經交給accessDecisionManager了,下文中會講述。

    4,來看看authentication-provider的實現:


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

        
    }

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

    5,對于資源的訪問權限的定義,我們通過實現FilterInvocationSecurityMetadataSource這個接口來初始化數據。

    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;

    /** *//**
     * 
     * 此類在初始化時,應該取到所有資源及其對應角色的定義
     * 
     * 
    @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這兩個資源,需要ROLE_ADMIN角色的用戶才能訪問。
    這個類中,還有一個最核心的地方,就是提供某個資源對應的權限定義,即getAttributes方法返回的結果。注意,我例子中使用的是AntUrlPathMatcher這個path matcher來檢查URL是否與資源定義匹配,事實上你還要用正則的方式來匹配,或者自己實現一個matcher。

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

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



    }



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

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

    Feedback

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

    eqweweqw  回復  更多評論   


    主站蜘蛛池模板: av片在线观看永久免费| 一区二区视频在线免费观看| 84pao国产成视频免费播放| 亚洲另类激情综合偷自拍图| a级毛片高清免费视频| 亚洲国产综合无码一区| 国产一级淫片a免费播放口| 亚洲AV日韩AV鸥美在线观看| 黄网站免费在线观看| 亚洲色偷偷av男人的天堂| 免费观看激色视频网站bd | 亚洲欧美国产国产综合一区| 精品久久久久成人码免费动漫| 亚洲日本乱码卡2卡3卡新区| 日韩精品视频免费网址| 美女露隐私全部免费直播| 亚洲精品一级无码中文字幕| 成人无码WWW免费视频| 精品日韩亚洲AV无码 | 久久久精品免费视频| 亚洲系列国产精品制服丝袜第| 国产免费不卡视频| 亚洲AV成人片无码网站| 亚洲熟妇少妇任你躁在线观看无码 | 亚洲日本乱码在线观看| 99精品视频在线观看免费播放 | 免费国产黄网站在线看| 亚洲色精品aⅴ一区区三区| 5555在线播放免费播放| 亚洲av永久无码精品秋霞电影秋| 亚洲欧洲久久久精品| 91成人在线免费观看| 亚洲丰满熟女一区二区哦| 亚洲无人区一区二区三区| 国产精品免费精品自在线观看| 欧洲亚洲国产精华液| 久久精品国产精品亚洲蜜月| 啦啦啦手机完整免费高清观看| 成人自慰女黄网站免费大全| 亚洲av永久无码天堂网| 亚洲视频在线免费|