2013-03-08 6 views
2

권한/인증을 위해 스프링 보안 및 폼 기반 로그인을 사용하는 스프링 MVC 애플리케이션이 있습니다.URL을 통한 스프링 보안 인증

는 지금은 토큰이 사용자에게 고유하므로 추가 정보없이 액세스 할 수 있어야합니다 토큰을 포함하는 특별한 URL 추가 할 :

http://myserver.com/special/5f6be0c0-87d7-11e2-9e96-0800200c9a66/text.pdf

을 어떻게 봄 보안에를 구성해야 할 사용자 인증을 위해 그 토큰을 사용합니까?

+0

을 기준으로 인증 하시겠습니까? –

+0

예, 사용자 정의 UserDetailsService를 사용하여 DB에서이 토큰을 통해 사용자를로드하고 로그인/비밀번호로 로그인 한 것처럼 완전히 인증합니다. –

+1

URL을 기반으로 사용자를 완전히 인증하는 것은 좋지 않습니다. 그 파일에 대한 액세스 권한을 제공하기 위해이 파일을 사용하고 있다면 충분할 것입니다. 그러나 일반적으로 전체 로그인으로 만 할 수있는 다른 작업을 수행 할 수 있도록 허용한다면주의해야합니다. –

답변

1

사용자 정의 사전 인증 필터를 정의해야합니다. http 태그 내에서 보안 응용 프로그램의 맥락에서

:

<custom-filter position="PRE_AUTH_FILTER" ref="preAuthTokenFilter" /> 

다음 (approprietly하고 해당 속성) 필터 빈을 정의

<beans:bean class="com.yourcompany.PreAuthTokenFilter" 
     id="preAuthTokenFilter"> 
    <beans:property name="authenticationDetailsSource" ref="authenticationDetailsSource" /> 
    <beans:property name="authenticationManager" ref="authenticationManager" /> 
    <beans:property name="authenticationEntryPoint" ref="authenticationEntryPoint"/> 
</beans:bean> 

은 사용자 정의 필터는

public class PreAuthTokenFilter extends GenericFilterBean { 

private AuthenticationEntryPoint authenticationEntryPoint; 
private AuthenticationManager authenticationManager; 
private AuthenticationDetailsSource authenticationDetailsSource = new WebAuthenticationDetailsSource(); 

@Override 
public void doFilter(ServletRequest req, ServletResponse resp, 
        FilterChain chain) throws IOException, ServletException { 
    HttpServletRequest request = (HttpServletRequest) req; 
    HttpServletResponse response = (HttpServletResponse) resp; 

    String token = getTokenFromHeader(request);//your method 

    if (StringUtils.isNotEmpty(token)) { 
     /* get user entity from DB by token, retrieve its username and password*/ 

     if (isUserTokenValid(/* some args */)) { 
      try { 
       UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password); 
       authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request)); 
       Authentication authResult = this.authenticationManager.authenticate(authRequest); 
       SecurityContextHolder.getContext().setAuthentication(authResult); 
      } catch (AuthenticationException e) { 
      } 
     } 
    } 

    chain.doFilter(request, response); 
} 

/* 
other methods 
*/ 
GenericFilterBean

에서 확장 만들기

비밀번호를 원하지 않거나 검색 할 수없는 경우, D는 PARAM (주)로만 이름을받을 것이다 AbstractAuthenticationToken 자신을 만들고 UsernamePasswordAuthenticationToken 대신이 기능을 사용하려면 사용자가 프로그래밍 방식으로 사용자는이 토큰에

public class PreAuthToken extends AbstractAuthenticationToken { 

    private final Object principal; 

    public PreAuthToken(Object principal) { 
     super(null); 
     super.setAuthenticated(true); 
     this.principal = principal; 
    } 

    @Override 
    public Object getCredentials() { 
     return ""; 
    } 

    @Override 
    public Object getPrincipal() { 
     return principal; 
    } 
} 
1

사용자 정의 PreAuthenticatedProcessingFilter 및 PreAuthenticatedAuthenticationProvider를 제공 할 수 있습니다. 자세한 내용은 Pre-Authentication Scenarios을 참조하십시오.

0

이 문제점이 발생하여 Spring Security RembereMe Service 인프라의 사용자 정의 구현을 사용하여 해결했습니다. 여기 당신이해야 할 일이 있습니다.

  • 자신의 Authentication 객체

    공용 클래스 LinkAuthentication 정의가 AbstractAuthenticationToken 확장 { @Override 공공 개체 getCredentials() { 는 null;

    @Override 
    public Object getPrincipal() 
    { 
    
        return the prncipal that that is passed in via the constructor 
    } 
    

    }

    }

사용자 지정 인증 공급자를 정의하기 위해 스프링 보안 XML의 나머지 나머지를 해킹

public class LinkRememberMeService implements RememberMeServices, LogoutHandler 
{  
    /** 
    * It might appear that once this method is called and returns an authentication object, that authentication should be finished and the 
    * request should proceed. However, spring security does not work that way. 
    * 
    * Once this method returns a non null authentication object, spring security still wants to run it through its authentication provider 
    * which, is totally brain dead on the part of Spring this, is why there is also a 
    * LinkAuthenticationProvider 
    * 
    */ 
    @Override 
    public Authentication autoLogin(HttpServletRequest request, HttpServletResponse response) 
    { 
     String accessUrl = ServletUtils.getApplicationUrl(request, "/special/"); 
     String requestUrl = request.getRequestURL().toString(); 
     if (requestUrl.startsWith(accessUrl)) 
     { 
      // take appart the url extract the token, find the user details object 
        // and return it. 
      LinkAuthentication linkAuthentication = new LinkAuthentication(userDetailsInstance); 
      return linkAuthentication; 
     } else 
     { 
      return null; 
     } 
    } 

    @Override 
    public void loginFail(HttpServletRequest request, HttpServletResponse response) 
    { 
    } 

    @Override 
    public void loginSuccess(HttpServletRequest request, HttpServletResponse response, Authentication successfulAuthentication) 
    { 
    } 

    @Override 
    public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) 
    { 
    } 
} 


public class LinkAuthenticationProvider implements AuthenticationProvider 
{ 

    @Override 
    public Authentication authenticate(Authentication authentication) throws AuthenticationException 
    { 
     // Spring Security is totally brain dead and over engineered 
     return authentication; 
    } 

    @Override 
    public boolean supports(Class<?> authentication) 
    { 
     return LinkAuthentication.class.isAssignableFrom(authentication); 
    } 

} 

을 정의하고 사용자 정의 나에게 서비스를 기억한다.

P. URL에서 GUID의 base64 인코딩을 수행하면 길이가 약간 짧아집니다. Apache commons codec base64 바이너리 인코더/디코더를 사용하면보다 안전한 URL 링크를 수행 할 수 있습니다.

public static String toBase64Url(UUID uuid) 
{ 
    return Base64.encodeBase64URLSafeString(toBytes(uuid)); 
}