在 Spring Security 中接收令牌的基本身份验证

Posted

技术标签:

【中文标题】在 Spring Security 中接收令牌的基本身份验证【英文标题】:Basic Auth to Receive Token in Spring Security 【发布时间】:2015-08-23 04:14:38 【问题描述】:

我正在实现用户必须进行身份验证的 RESTful API。我希望用户发布他们的凭据以接收 JSON Web 令牌 (JWT),然后将其用于会话的其余部分。我还没有找到任何好的信息来源来设置它。特别是,我在使用过滤器时遇到了问题。有人有任何信息或教程可以帮助我进行设置吗?

【问题讨论】:

【参考方案1】:

Stormpath 的人们有一个非常简单的解决方案来实现 Oauth。请查看Using Stormpath for API Authentication。

总而言之,您的解决方案将如下所示:

    您将使用Stormpath Java SDK 轻松委派您的所有用户管理需求。 当用户按下登录按钮时,您的前端将通过其 REST API 将凭据安全地发送到您的后端。
      顺便说一句,您还可以将登录/注册/注销功能完全委托给Servlet Plugin。 Stormpath 还支持 Google、Facebook、LinkedIn 和 Github 登录。

    然后,您的后端将尝试根据 Stormpath 后端对用户进行身份验证,结果将返回 access token

    /**
     * Authenticates via username (or email) and password and returns a new access token using the Account's ApiKey
     */
    public String getAccessToken(String usernameOrEmail, String password) 
        ApiKey apiKey = null;
        try 
            AuthenticationRequest request = new UsernamePasswordRequest(usernameOrEmail, password);
            AuthenticationResult result = application.authenticateAccount(request);
            Account account = result.getAccount();
            ApiKeyList apiKeys = account.getApiKeys();
            for (ApiKey ak : apiKeys) 
                apiKey = ak;
                break;
            
            if (apiKey == null) 
                //this account does not yet have an apiKey
                apiKey = account.createApiKey();
            
         catch (ResourceException exception) 
            System.out.println("Authentication Error: " + exception.getMessage());
            throw exception;
        
    
        return getAccessToken(apiKey);
    
    
    private String getAccessToken(ApiKey apiKey) 
        HttpRequest request = createOauthAuthenticationRequest(apiKey);
        AccessTokenResult accessTokenResult = (AccessTokenResult) application.authenticateApiRequest(request);
        return accessTokenResult.getTokenResponse().getAccessToken();
    
    
    
    private HttpRequest createOauthAuthenticationRequest(ApiKey apiKey) 
        try 
            String credentials = apiKey.getId() + ":" + apiKey.getSecret();
    
            Map<String, String[]> headers = new LinkedHashMap<String, String[]>();
            headers.put("Accept", new String[]"application/json");
            headers.put("Content-Type", new String[]"application/x-www-form-urlencoded");
            headers.put("Authorization", new String[]"Basic " + Base64.encodeBase64String(credentials.getBytes("UTF-8")));
    
            Map<String, String[]> parameters = new LinkedHashMap<String, String[]>();
            parameters.put("grant_type", new String[]"client_credentials");
    
            HttpRequest request = HttpRequests.method(HttpMethod.POST)
                    .headers(headers)
                    .parameters(parameters)
                    .build();
            return request;
         catch (Exception e) 
            e.printStackTrace();
            return null;
        
    
    

    然后,对于每个经过身份验证的请求,您的后端都会这样做:

    /** This is your protected API */
    public void sayHello(String accessToken) throws OauthAuthenticationException 
        try 
            if (verify(accessToken)) 
                doStartEngines(); //Here you will actually call your internal doStartEngines() operation
            
         catch (OauthAuthenticationException e) 
            System.out.print("[Server-side] Engines not started. accessToken could not be verified: " + e.getMessage());
            throw e;
        
    
    
    private boolean verify(String accessToken) throws OauthAuthenticationException 
        HttpRequest request = createRequestForOauth2AuthenticatedOperation(accessToken);
        OauthAuthenticationResult result = application.authenticateOauthRequest(request).execute();
        System.out.println(result.getAccount().getEmail() + " was successfully verified");
        return true;
    
    
    private HttpRequest createRequestForOauth2AuthenticatedOperation(String token) 
        try 
            Map<String, String[]> headers = new LinkedHashMap<String, String[]>();
            headers.put("Accept", new String[]"application/json");
            headers.put("Authorization", new String[]"Bearer " + token);
            HttpRequest request = HttpRequests.method(HttpMethod.GET)
                    .headers(headers)
                    .build();
            return request;
         catch (Exception e) 
            e.printStackTrace();
            return null;
        
    
    

所有这些都不需要任何特殊的 Spring Security 配置,这是可以在任何框架中运行的纯 Java 代码。

请查看here了解更多信息。

希望有帮助!

免责声明,我是 Stormpath 的活跃贡献者。

【讨论】:

我需要使用 Spring Security,所以这不适合我的需要。不过,我要感谢您出色而详细的回复。 Mrks_,这与 Spring Security 兼容。您将不会在您的应用程序中使用 Spring 支持的 Oauth 解决方案,但您可以完全将它与 Spring Security 一起使用,这根本不排除它。很高兴能提供帮助。【参考方案2】:

这是来自 Spring Security OAuth github 的工作示例代码。 https://github.com/spring-projects/spring-security-oauth/tree/master/tests/annotation/jwt

您可能甚至不需要像上面示例中所示的那样弄乱过滤器。如果您有自定义需求,请发布一些示例代码。

【讨论】:

这些例子帮了大忙。我以前不知道他们。谢谢你的链接。 太棒了!很高兴能提供帮助:-)

以上是关于在 Spring Security 中接收令牌的基本身份验证的主要内容,如果未能解决你的问题,请参考以下文章

在 Spring Security 中获取访问令牌

如何在 Spring Security 中将令牌转换为身份验证?

在 Spring Security 中检查令牌的 NullPointerException

在 spring-security 中更改 csrf 令牌

如何在 Spring Security 中刷新令牌

Spring security oauth 令牌提取