SpringSecurity 사용 기록 (5) -- 설정

21696 단어 SpringSecurity
기본 설정 을 통 해 설정 합 니 다:
namespace (security 3.0 입 니 다. 인터넷 에서 도 일부 형제 가 묘사 한 것 은 3.0 이지 만 항상 제 가 있 는 namespace 설정 에 부합 되 지 않 습 니 다):
           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 설정 에 따 른 기본 보안 필터 chain):
auto - config = true
 
   
   
   
 

기본 필 터 를 사용 한 것 이다.
내 가 처음에 생각 한 것 은 로 컬 login 정보 (spring security 를 호출 하 는 login 방법 이 아 닌) 를 spring security 의 검증 필터 에 전송 하 는 것 이다.
여기 서 가장 중요 한 문 제 는 필 터 를 밀봉 하 는 것 입 니 다. (또는 그들 이 어떤 필터 가 작용 하 는 지 만 알 고 있 습 니 다)
Alias
Filter Class
Namespace 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 는 FORMLOGIN_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 에 대응 하 는 지 잘 보 세 요!
이어서:
내 클래스 MyUsernamePassword Authentication Filter 구현 (내 설명 방식 은 필요 한 곳, 가입 하 는 방식):
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;
    }
    
    
}

여기 서 주목 해 야 할 것 은 몇 개의 필드 입 니 다.
   
   
이 두 필드 는 인증 이 성공 하거나 실 패 했 을 때 방향 을 바 꾸 는 페이지 입 니 다. "/" 로 시작 하 는 것 을 주의해 야 합 니 다. 그렇지 않 으 면 Abstract Authentication TargetUrl RequestHandler 에서 set Default TargetUrl 방법 을 호출 할 때 "default Target must start with '/' or with 'http (s)' 의 이상 을 던 집 니 다!
기본적으로 FORMLOGIN_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 는 기본 Provider Manager 를 사용 합 니 다. 이 관리 자 는 어디에서 사용 합 니까?
MyUsernamePassword AuthenticationFilter 의 attempty Authentication 방법의 마지막 줄 을 보십시오. 지정 한 authentication - manager 를 가 져 옵 니 다.getAuthenticationManager 는 부모 클래스 Abstract AuthenticationProcessingFilter 에서 물 려 받 았 습 니 다.따라서 우리 의 < authentication - manager alias = "authentication Manager" > 에 별명 authentication Manager 가 지정 되 어 있 습 니 다. my filter 에 속성 을 설정 한 참조 < beans: property name = "authentication Manager" ref = "authentication Manager" / > 를 참조 한 다음 Provider 를 통 해 사용자 정 보 를 참조 하여 서 비 스 를 검증 할 수 있 습 니 다.(eg: 사용자 정보 획득 과 검증)! 이 곳 은 실제 Method Template 모드 를 사 용 했 습 니 다 (Abstract AuthenticationManager 에서 템 플 릿 함수 doAuthentication 을 설정 하고 Provider Manager 에서 이 루어 졌 습 니 다).
여기 서 우리 의 서비스 가 어떻게 호출 되 었 는 지 설명 하기 어렵 습 니 다. 우 리 는 < authentication - provider user - service - ref = 'my UserDetails Service' / > 를 설정 하 였 습 니 다.
우리 의 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);
    }

}

Dao AuthenticationProvider 의 userDetailsService 를 통 해 우리 의 UserDetailsService 와 연 결 됩 니 다.(어 쩔 수 없 이 AbstractUserDetails AuthenticationProvider 에 템 플 릿 함수 retrieveUser 가 설정 되 어 있 고, Dao AuthenticationProvider 가 구현 되 었 으 며, retrieveUser 방법 으로 UserDetails Service. loadUserByUsername 을 호출 한 후, AbstractUserDetails AuthenticationProvider. authenticate 방법 으로 검증 되 었 습 니 다).
다음은 검증 결과 입 니 다. 성공 여 부 를 보고 filter chain 에 들 어 갑 니 다.

좋은 웹페이지 즐겨찾기