3

Spring Security とフォームベースのログインを承認/認証に使用する Spring MVC アプリがあります。

トークンはユーザーに固有であるため、追加情報なしでアクセスできるトークンを含む特別な URL を追加したいと思います。

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

ユーザー認証にそのトークンを使用するには、Spring Security をどのように構成する必要がありますか?

4

3 に答える 3

1

カスタムの PreAuthenticatedProcessingFilter と PreAuthenticatedAuthenticationProvider を提供できます。詳細については、認証前のシナリオの章を参照してください。

于 2013-03-08T10:43:31.680 に答える
1

カスタム事前認証フィルターを定義する必要があります。

httpタグ内のセキュリティ アプリ コンテキスト:

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

次に、フィルター Bean (およびそのプロパティ) を適切に定義します。

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

GenericFilterBean から拡張されたカスタム フィルターを作成します。

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

パスワードを取得したくない、または取得できない場合は、AbstractAuthenticationTokenユーザー名のみを param (プリンシパル) として受け取り、代わりに使用する独自のパスワードを作成する必要があり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;
    }
}
于 2016-05-13T08:15:48.273 に答える
0

私はこの問題に遭遇し、Spring Security RembereMe サービス インフラストラクチャのカスタム実装を使用して解決しました。これがあなたがする必要があることです。

  • 独自の認証オブジェクトを定義する

    public class LinkAuthentication extends AbstractAuthenticationToken { @Override public Object getCredentials() { return null; }

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

    }

定義

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

}

Spring セキュリティ xml の残りの部分をハックして、カスタム認証プロバイダーとカスタムの記憶サービスを定義します。

PS URL の GUID を base64 でエンコードすると、数文字短くなります。Apache commons コーデック base64 バイナリ エンコーダー/デコーダーを使用して、より安全な URL リンクを行うことができます。

public static String toBase64Url(UUID uuid)
{
    return Base64.encodeBase64URLSafeString(toBytes(uuid));
}
于 2013-03-09T16:07:20.180 に答える