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

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

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

    無極,無際,無跡

      BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
      3 Posts :: 8 Stories :: 10 Comments :: 0 Trackbacks
    研究了好長時間,不知道從哪里下手。新的版本,很多東西在網上找不到,只能看他們的文檔,當然這些文檔相當不錯,就看是否耐心的研究了!總是有急躁的心理作祟,不能專心研讀,卻處處碰壁,效率上反而未達預期效果!
    終于,在無數次的沮喪下,稍微看到了點光亮!前面的文章太過皮毛,接下來的一些,希望能更加實際的,更加深入的分析每一個過程!

    一直通過默認配置進行設置:
    namespace(是security 3.0,網上也看到一些兄弟描述的是3.0,但是總是不符合我這里的namespace配置):
    <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(這是用來根據namespace設置的基本的security過濾器chain):
    auto-config=true時,就相當于
      <http>
        <form-login />
        <http-basic />
        <logout />
      </http>
    也就是使用了默認的過濾器。
    我最開始的想法是能夠把本地的login信息(不是調用spring security的login方法),傳入到spring security的驗證過濾器里面。
    這里有一個比較關鍵的問題,就是封裝他們的過濾器(或者僅僅是知道他們到底是哪些過濾器在起作用):
    表1
    AliasFilter ClassNamespace Element or Attribute
    CHANNEL_FILTER ChannelProcessingFilter http/intercept-url@requires-channel
    CONCURRENT_SESSION_FILTER ConcurrentSessionFilter session-management/concurrency-control
    SECURITY_CONTEXT_FILTER SecurityContextPersistenceFilter http
    LOGOUT_FILTER LogoutFilter http/logout
    X509_FILTER X509AuthenticationFilter http/x509
    PRE_AUTH_FILTER AstractPreAuthenticatedProcessingFilter Subclasses N/A
    CAS_FILTER CasAuthenticationFilter N/A
    FORM_LOGIN_FILTER UsernamePasswordAuthenticationFilter http/form-login
    BASIC_AUTH_FILTER BasicAuthenticationFilter http/http-basic
    SERVLET_API_SUPPORT_FILTER SecurityContextHolderAwareFilter http/@servlet-api-provision
    REMEMBER_ME_FILTER RememberMeAuthenticationFilter http/remember-me
    ANONYMOUS_FILTER AnonymousAuthenticationFilter http/anonymous
    SESSION_MANAGEMENT_FILTER SessionManagementFilter session-management
    EXCEPTION_TRANSLATION_FILTER ExceptionTranslationFilter http
    FILTER_SECURITY_INTERCEPTOR FilterSecurityInterceptor http
    SWITCH_USER_FILTER SwitchUserFilter N/A


    (最開始看的時候,把這個表格忽略了,現在看來這些就是我們想要的!)
    我們的驗證過程,就是按照這樣的順序進行的。自上而下進行。

    如果我們要自己定制相應的驗證處理方法(在過濾器里面),我們就可以對照上面的過濾器,覆蓋相應的接口方法。
    根據我的處理過程,主要是用戶名密碼的驗證過程,我大體描述一下自己的配置和處理過程:
    1.配置namespace的標簽:
      <http  use-expressions="true" ><!-- This is not the default value -->
           <custom-filter position="FORM_LOGIN_FILTER" ref="myFilter"/> <!--This is my own filter which just extends AbstractAuthenticationProcessingFilter as what UsernamePasswordAuthenticationFilter does.-->
           <intercept-url pattern="/test/**"  access="hasRole('ROLE_MY')"/><!-- I tested that what is role,and how I can use it.So ROLE_MY is just a role name I defined.-->
           <intercept-url pattern="/login.jsp*" access="permitAll" />
           <logout />
           <anonymous />
           <http-basic />
      </http>
    這里的問題是,要定制自己的過濾器,就要通過<custom-filter/>,然后對照 表1 中指定的position,覆蓋默認的filter。
    2.我的form-login  filter配置(這些配置都是在application-security.xml文件中)為:
    <beans:bean id="myFilter"
          class="com.saveworld.authentication.filters.MyUsernamePasswordAuthenticationFilter">
        <beans:property name="defaultTargetUrl"  value="/default.jsp" />
        <beans:property name="defaultFailureUrl"  value="/error.jsp" />
        <beans:property name="authenticationManager" ref="authenticationManager" />
        <beans:property name="filterProcessesUrl" value="/j_spring_security_check" />
        <beans:property name="continueChainBeforeSuccessfulAuthentication" value="false" />
      </beans:bean>

    NOTE:
    在這里有個問題就是: filter position conflicts!
    如果使用這樣的配置
    <http auto-config='true'>
       <custom-filter position="FORM_LOGIN_FILTER" ref="myFilter"/>
    </http>
    自定義的filter對應的position是FORM_LOGIN_FILTER
    但是因為使用了auto-config='true',所以默認有<form-login />,which is on the position FORM_LOGIN_FILTER!
    這時就會出現position conflicts問題了。當然,如果你沒有設置auto-config='true',但是卻自己設置了<form-login />,呵呵,這個情況就是自己大意了,還是有了position conflicts的異常,所以,好好看看上面的表格是相當必要的,看清楚每個position默認都對應那些namespace,都是對應的哪些filter!

    接著:
    我的類MyUsernamePasswordAuthenticationFilter實現(我的說明方式就按照哪里需要,哪里加入的方式了):
    package com.saveworld.authentication.filters;

    import java.io.IOException;

    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;

    import org.springframework.security.authentication.AuthenticationServiceException;
    import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
    import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
    import org.springframework.security.core.Authentication;
    import org.springframework.security.core.AuthenticationException;
    import org.springframework.security.core.context.SecurityContextHolder;
    import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
    import org.springframework.security.web.authentication.AuthenticationFailureHandler;
    import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
    import org.springframework.security.web.authentication.NullRememberMeServices;
    import org.springframework.security.web.authentication.RememberMeServices;
    import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
    import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
    import org.springframework.security.web.util.TextEscapeUtils;
    import org.springframework.util.Assert;

    import com.saveworld.authentication.handlers.MySavedRequestAwareAuthenticationSuccessHandler;
    import com.saveworld.authentication.handlers.MySimpleUrlAuthenticationFailureHandler;

    public class MyUsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter{
        //~ Static fields/initializers =====================================================================================

        public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "username";
        public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "password";
        public static final String SPRING_SECURITY_LAST_USERNAME_KEY = "SPRING_SECURITY_LAST_USERNAME";

        private String usernameParameter = SPRING_SECURITY_FORM_USERNAME_KEY;
        private String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY;
        private boolean postOnly = true;
       
        private boolean allowSessionCreation = true;
       
        private String defaultTargetUrl = "/";
        private String defaultFailureUrl = "/login.jsp";
       
        private AuthenticationSuccessHandler successHandler = null;
        private AuthenticationFailureHandler failureHandler = null;
       
       
        private RememberMeServices rememberMeServices = null;
       
        //~ Constructors ===================================================================================================

        public MyUsernamePasswordAuthenticationFilter() {
            //初始化
            super("/j_spring_security_check");
            this.rememberMeServices = (super.getRememberMeServices() == null)
                                         ? new NullRememberMeServices():super.getRememberMeServices();
           
        }

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

        public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
            if (postOnly && !request.getMethod().equals("POST")) {
                throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
            }

            String username = obtainUsername(request);
            String password = obtainPassword(request);

            if (username == null) {
                username = "";
            }

            if (password == null) {
                password = "";
            }

            username = username.trim();

            UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);

            // Place the last username attempted into HttpSession for views
            HttpSession session = request.getSession(false);

            if (session != null || getAllowSessionCreation()) {
                request.getSession().setAttribute(SPRING_SECURITY_LAST_USERNAME_KEY, TextEscapeUtils.escapeEntities(username));
            }

            // Allow subclasses to set the "details" property
            setDetails(request, authRequest);

            return this.getAuthenticationManager().authenticate(authRequest);
        }

       
       
        public void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
                Authentication authResult) throws IOException, ServletException {

            if (logger.isDebugEnabled()) {
                logger.debug("Authentication success. Updating SecurityContextHolder to contain: " + authResult);
            }
           
            SecurityContextHolder.getContext().setAuthentication(authResult);

            rememberMeServices.loginSuccess(request, response, authResult);

            // Fire event
            if (this.eventPublisher != null) {
                eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
            }
            if(successHandler == null){
                successHandler = new MySavedRequestAwareAuthenticationSuccessHandler(getDefaultTargetUrl());
            }
            successHandler.onAuthenticationSuccess(request, response, authResult);
        }
       
        public void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
                AuthenticationException failed) throws IOException, ServletException {
            SecurityContextHolder.clearContext();
           
            if(failureHandler == null){
                failureHandler = new MySimpleUrlAuthenticationFailureHandler(getDefaultFailureUrl());
            }
           
            if (logger.isDebugEnabled()) {
                logger.debug("Authentication request failed: " + failed.toString());
                logger.debug("Updated SecurityContextHolder to contain null Authentication");
                logger.debug("Delegating to authentication failure handler" + failureHandler);
            }

            HttpSession session = request.getSession(false);

            if (session != null || allowSessionCreation) {
                request.getSession().setAttribute(SPRING_SECURITY_LAST_EXCEPTION_KEY, failed);
            }

            rememberMeServices.loginFail(request, response);

            failureHandler.onAuthenticationFailure(request, response, failed);
        }
       
       
        /**
         * Enables subclasses to override the composition of the password, such as by including additional values
         * and a separator.<p>This might be used for example if a postcode/zipcode was required in addition to the
         * password. A delimiter such as a pipe (|) should be used to separate the password and extended value(s). The
         * <code>AuthenticationDao</code> will need to generate the expected password in a corresponding manner.</p>
         *
         * @param request so that request attributes can be retrieved
         *
         * @return the password that will be presented in the <code>Authentication</code> request token to the
         *         <code>AuthenticationManager</code>
         */
        protected String obtainPassword(HttpServletRequest request) {
            return request.getParameter(passwordParameter);
        }

        /**
         * Enables subclasses to override the composition of the username, such as by including additional values
         * and a separator.
         *
         * @param request so that request attributes can be retrieved
         *
         * @return the username that will be presented in the <code>Authentication</code> request token to the
         *         <code>AuthenticationManager</code>
         */
        protected String obtainUsername(HttpServletRequest request) {
            return request.getParameter(usernameParameter);
        }

        /**
         * Provided so that subclasses may configure what is put into the authentication request's details
         * property.
         *
         * @param request that an authentication request is being created for
         * @param authRequest the authentication request object that should have its details set
         */
        protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) {
            authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
        }

        /**
         * Sets the parameter name which will be used to obtain the username from the login request.
         *
         * @param usernameParameter the parameter name. Defaults to "j_username".
         */
        public void setUsernameParameter(String usernameParameter) {
            Assert.hasText(usernameParameter, "Username parameter must not be empty or null");
            this.usernameParameter = usernameParameter;
        }

        /**
         * Sets the parameter name which will be used to obtain the password from the login request..
         *
         * @param passwordParameter the parameter name. Defaults to "j_password".
         */
        public void setPasswordParameter(String passwordParameter) {
            Assert.hasText(passwordParameter, "Password parameter must not be empty or null");
            this.passwordParameter = passwordParameter;
        }

        /**
         * Defines whether only HTTP POST requests will be allowed by this filter.
         * If set to true, and an authentication request is received which is not a POST request, an exception will
         * be raised immediately and authentication will not be attempted. The <tt>unsuccessfulAuthentication()</tt> method
         * will be called as if handling a failed authentication.
         * <p>
         * Defaults to <tt>true</tt> but may be overridden by subclasses.
         */
        public void setPostOnly(boolean postOnly) {
            this.postOnly = postOnly;
        }

        public final String getUsernameParameter() {
            return usernameParameter;
        }

        public final String getPasswordParameter() {
            return passwordParameter;
        }

        public String getDefaultTargetUrl() {
            return defaultTargetUrl;
        }

        public void setDefaultTargetUrl(String defaultTargetUrl) {
            this.defaultTargetUrl = defaultTargetUrl;
        }

        public String getDefaultFailureUrl() {
            return defaultFailureUrl;
        }

        public void setDefaultFailureUrl(String defaultFailureUrl) {
            this.defaultFailureUrl = defaultFailureUrl;
        }
       
       
    }

    這里要關注的就是幾個字段:
        <beans:property name="defaultTargetUrl"  value="/default.jsp" />
        <beans:property name="defaultFailureUrl"  value="/error.jsp" />
    這兩個字段是指定驗證成功或失敗后轉向的頁面,這里要注意是以“/”開頭,否則在AbstractAuthenticationTargetUrlRequestHandler中調用setDefaultTargetUrl方法時會拋出"defaultTarget must start with '/' or with 'http(s)'"的異常!
    默認情況下,FORM_LOGIN_FILTER對應的target url和failure url都是通過 <form-login />中的default-target-url,authentication-failure-url指定,也可以通過指定authentication-success-handler-ref和authentication-failure-handler-ref來實現認證成功和失敗之后的處理方式.在我的filter中,是自定義了兩個handler分別對應成功的和失敗的驗證。

    3.用戶信息獲取和驗證:
      <authentication-manager alias="authenticationManager">
        <authentication-provider user-service-ref='myUserDetailsService'/>
      </authentication-manager>
      <beans:bean id="myUserDetailsService" class="com.saveworld.userdetails.MyUserDetailsService"></beans:bean>
    這個指定的authentication-manager是使用默認的ProviderManager,這個manager是在哪里使用的呢?
    看看MyUsernamePasswordAuthenticationFilter中的attemptAuthentication方法的最后一行,這里是獲取指定的authentication-manager。getAuthenticationManager是從父類AbstractAuthenticationProcessingFilter繼承過來的。所以,我們的<authentication-manager alias="authenticationManager">中就指定了一個別名authenticationManager,在myfilter中設置屬性的引用<beans:property name="authenticationManager" ref="authenticationManager" />,然后我們就可以通過Provider引用我們自己的用戶信息驗證service了(eg:用戶信息獲取和驗證)!這里實際是使用了Method Template模式(AbstractAuthenticationManager中設定模板函數doAuthentication,ProviderManager中做了實現)。
    這里難免要說明一下,我們的Service是如何被調用的,我們做了配置<authentication-provider user-service-ref='myUserDetailsService'/>
    指定了我們的UserDetailsService,類實現(為了測試和理解,The easier the better!):
    package com.saveworld.userdetails;

    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;

    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 MyUserDetailsService implements UserDetailsService{
       
        private HashMap<String, User> userDetails = new HashMap<String, User>();
        private HashMap<String, List<GrantedAuthority>> userAuthorities = new HashMap<String, List<GrantedAuthority>>();
       
        public MyUserDetailsService(){
            //Make up a user named 'rod' with 'rod' as his password!
            //
            String username = "rod";
            String password = "1";
            boolean enabled = true;
            //purview for rod
            GrantedAuthority specAuth = new GrantedAuthorityImpl("ROLE_MY");
            List<GrantedAuthority> rodsAuthsList = new ArrayList<GrantedAuthority>();
            rodsAuthsList.add(specAuth);
    //        userAuthorities.put("rod", rodsAuthsList);
            userDetails.put("rod", new User(username, password, enabled, true, true, true, rodsAuthsList));
        }
       
       
        public UserDetails loadUserByUsername(String username)
                throws UsernameNotFoundException, DataAccessException {
            System.out.println("驗證從此地過了一遭");
            return userDetails.get(username);
        }

    }
    通過DaoAuthenticationProvider中的userDetailsService關聯我們的UserDetailsService(不得不提的是,AbstractUserDetailsAuthenticationProvider中有設定了模板函數retrieveUser,DaoAuthenticationProvider進行了實現,通過retrieveUser方法調用UserDetailsService.loadUserByUsername,然后在AbstractUserDetailsAuthenticationProvider.authenticate方法進行驗證)。
    接下來就是看驗證的結果了,是否成功,進入filter chain中。
    這一切就這么有條不紊的進行了!呵呵,總算是有點成果了!有了一點點感性的認識了!上面的描述中難免會有些混亂,但是盡量是哪里需要,哪里就做說明!

    下篇中說明entrypoint的用處吧!
    posted on 2010-01-19 14:19 taochen 閱讀(18823) 評論(3)  編輯  收藏 所屬分類: java軟件架構

    Feedback

    # re: SpringSecurity使用記錄(五)-- 配置 2010-09-01 14:37 楊彩
    這是真好文!thankyou  回復  更多評論
      

    # re: SpringSecurity使用記錄(五)-- 配置 2010-10-08 19:26 南方不下雪
    能將完整的配制發表出來嗎  回復  更多評論
      

    # re: SpringSecurity使用記錄(五)-- 配置 2013-08-21 18:57 ximlos
    首先非常感謝樓主把這篇帖子發表出來,讓我們一頭霧水的人可以有解決問題的思路了,但是我有個地方不太清楚,我把這句粘進去的時候提示有錯,是怎么回事呢?需要配置entrypoint嗎?
    <http use-expressions="true" >
    <custom-filter position="FORM_LOGIN_FILTER" ref="myFilter"/>


    錯誤:
    Multiple annotations found at this line:
    - Method 'setAuthenticationEntryPoint' is marked deprecated [config set: dncr-telco-web/web-context]
    - Method 'setSecurityContextRepository' is marked deprecated [config set: dncr-telco-web/web-context]
    - Method 'setUserAttribute' is marked deprecated [config set: dncr-telco-web/web-context]
    - Method 'setSessionAuthenticationStrategy' is marked deprecated [config set: dncr-telco-web/web-context]
    - Method 'setRequestCache' is marked deprecated [config set: dncr-telco-web/web-context]
    - No AuthenticationEntryPoint could be established. Please make sure you have a login mechanism configured through the namespace (such
    as form-login) or specify a custom AuthenticationEntryPoint with the 'entry-point-ref' attribute
    - Method 'setKey' is marked deprecated [config set: dncr-telco-web/web-context]

    謝謝樓主了  回復  更多評論
      

    主站蜘蛛池模板: 亚洲色无码国产精品网站可下载| 亚洲国产精品自在线一区二区| 亚洲AV无码专区在线亚 | 亚洲色精品VR一区区三区| 69国产精品视频免费| 亚洲精品乱码久久久久久自慰 | 亚洲成a人片在线不卡一二三区| 999在线视频精品免费播放观看| 亚洲日本一区二区三区| 污污网站免费观看| 亚洲美免无码中文字幕在线| **真实毛片免费观看 | 国产免费黄色大片| 国产成人精品亚洲| 亚洲第一区在线观看| 国产精品成人69XXX免费视频| 国产AV无码专区亚洲AV漫画 | 久久综合亚洲鲁鲁五月天| 免费人成视频在线观看网站| 亚洲成综合人影院在院播放| 大地资源免费更新在线播放| 在线91精品亚洲网站精品成人| 亚洲中文字幕伊人久久无码| 精品亚洲永久免费精品| 亚洲一区免费在线观看| 色吊丝永久在线观看最新免费| 国产精品亚洲五月天高清| 亚洲精品线路一在线观看| 可以免费观看的国产视频| 亚洲校园春色小说| 国产美女做a免费视频软件| jizz在线免费播放| 亚洲色偷偷av男人的天堂| 四色在线精品免费观看| 国产精品免费久久久久影院| 91嫩草私人成人亚洲影院| 国产亚洲精品免费| 午夜免费啪视频在线观看 | 国产日韩久久免费影院| 亚洲中文无码线在线观看| 免费h黄肉动漫在线观看|