管理身份验证令牌的最佳做法

时间:2017-02-16 15:52:32

标签: java rest authentication httpclient

我使用HttpCLient在Java中编写REST客户端,我访问的REST API需要每个REST操作的身份验证令牌。此令牌有效期为24小时。

我现在处理此问题的方法是调用" getAuth()"每次我需要进行REST调用时,这似乎是auth服务器上的开销。

如何方便地存储此身份验证令牌并管理其生命周期? 是否有任何记录的最佳实践?

我想到了以下解决方案

public class MySession {
    String user;
    String pass;
    public MySession(String user, String pass) {
        this.user = user;
        this.pass = pass;
    }

    public getAuth() {
        //user user, pass to get auth token 
    }
}

然后将sessions对象传递给任何需要该令牌的类。如果令牌已过期,请再次调用此方法

10 个答案:

答案 0 :(得分:7)

为简洁起见,我假设您正在调用一个无法更改的端点。您应该如何实现将在很大程度上取决于令牌是基于应用还是基于用户(共享应用实例上的所有用户一个令牌或每个用户一个令牌)。

如果它是整个应用程序的一个身份验证令牌:

  • 将其与生存时间戳一起存储在内存中(或者捕获令牌过期错误,请求新令牌并重试原始请求),如果它不存在则刷新/已过期
  • 如果您担心在应用程序重新启动后重新请求API令牌,还会将其存储在数据库中并在启动时加载(如果存在)

如果每个用户只有一个令牌:

  • 将它存储在您的用户会话中,这正是会话所用的内容,如果您正在为用户进行授权,那么他们将会有一个会话并且已经存在开销
  • 如果您不希望每次登录时都重新请求令牌,请将当前令牌存储在数据库中,并在登录时将其加载到会话中

答案 1 :(得分:4)

我假设您正在使用OAuth进行授权。无论您使用的是JWT还是其他令牌都与这种情况无关。

执行授权时,您将获得一个过期的access_token,并且根据您请求的授权类型(客户端凭据,授权代码,隐式,资源所有者),refresh_token。< / p>

客户端应保持access_token和到期日期。如果发出refresh_token,则必须保密(谨防为您的用例使用正确的授权)。

在后续通话中,您的客户端不应在每次通话时请求新令牌,而应使用存储的access_token

API开始返回401 Unauthorized后,access_token可能已过期。如果您有access_token,您的客户应尝试使用refresh_token刷新refresh_token

如果您没有refresh_token或刷新请求也失败,因为access_token不再有效,您可以执行新的授权流程。

您可以使用过期时间作为线索,通过刷新或通过新的完整授权流程来了解何时获取新的401 Unauthorized。这将避免access_token。在任何情况下,在使用有效public class TypeManager{ private static uint _ID = 0; private static Dictionary<string,uint> typemap = new Dictionary<string,uint>(); public static uint GetType<T>(List<T> types) { string key = ""; for(int i = 0; i < types.Count; ++i) key += types[i] + ">"; return GetType(key); } public static uint GetType(string key) { if(!typemap.ContainsKey(key)) { typemap[key] = _ID++; } return typemap[key]; } } 进行某些调用后收到此回复时,您的客户应该有一个后备政策。

答案 2 :(得分:3)

如果您担心数据库的点击次数太多,那么我假设有很多网络活动。

我不建议在您的情况下使用Session,而是将令牌存储在客户端的cookie中。

在高流量环境(我假设你的环境)中,使用Session会消耗大量服务器内存,并且可扩展性也是一个问题,必须在群集中保持会话同步。

正如@CássioMazzochiMolin所提到的,您可以使用内存缓存来存储任何特定于用户的数据和令牌。这将减少对数据库的命中,并且还允许您在需要时更轻松地扩展应用程序。

答案 3 :(得分:3)

我建议您使用以下方案:

1)首先,调用auth(username, password) rest api获取身份验证令牌。 如果给定的凭证没问题,那么只需使用HTTP 200响应代码将auth cookie发送回客户端。

2)然后,您可以调用protected rest apis。您需要每次都发送带有您请求的身份验证cookie。

3)Servlet过滤器(或类似的东西)检查每个传入的请求并验证令牌。如果令牌有效,则请求前进到rest方法,如果不是,则需要生成http 401/403响应。

我建议你不要编写自己的身份验证层。而不是安装和使用现有的。我建议你OpenAM。它是一个极好的开源访问管理系统。

我还建议您不要在服务器端打开会话以进行身份​​验证。如果您有10个客户端,则需要由服务器管理10个会话。这不是一个大问题。但是,如果你有100或1000或数百万个不同的客户端,那么你需要更多的内存来存储服务器上的会话。

答案 4 :(得分:2)

事实上的标准没有实现你自己的解决方案(安全性的基本规则:不实现你自己的东西!),但使用事实上的标准解决方案,即{{3 }}

网站上的文档,但基本的想法是,您只需要存储一个值(服务器的私钥),然后您可以验证服务器最初发出的每个声明(在您的情况下包含到期时间。)

答案 5 :(得分:2)

您可以创建管理器并在登录期间在本地线程中存储auth-cookie,如下面的代码所示。只要线程存在,您就可以从getAuth()获取cookie。

public class Manager {
    private static final ThreadLocal<String> SECURITY_CONTEXT = new ThreadLocal<>();

    public static void setAuth(String auth) {
        SECURITY_CONTEXT.set(auth);
    }

    public static String getAuth() {
        return SECURITY_CONTEXT.get();
    }

    public static void clear(){
        SECURITY_CONTEXT.remove();
    }
}

答案 6 :(得分:2)

你应该使用JsonWebToken(简称JWT)来做这种事情。 JWT已建立支持以设置到期日期。有很多库可以使用此方法,您可以阅读更多here

目前有4个java实现,所有这些实现都可以检查令牌是否仍然有效(exp check) enter image description here

答案 7 :(得分:2)

因此,如果我正确理解您正在为所有请求使用相同的令牌(这意味着只要您的应用启动并运行并且您刷新令牌,那么您应该没问题。我确实同样的问题,这就是我解决它的方法。我有一个单例类,它在应用程序启动时初始化一次,并在令牌失效时刷新令牌。我使用C#,Asp.NET MVC5和用于DI的AutoFac,但我确信你可以用Java和Spring做同样的事情。

Updating property of a singleton with Thread Safety

答案 8 :(得分:0)

使用json web令牌,在两个客户端之间交换信息。该令牌仅在24小时内保持活动状态,此后标题中的所有后续呼叫都将被拒绝。

答案 9 :(得分:-1)

  1. 每个请求的身份验证都是正确的方法,请考虑针对性能问题进行身份验证服务器扩展。
  2. 首次成功验证(用户名和密码)时,生成私有公钥对。将私钥存储为会话安全令牌(SST),并将公钥作为公共安全客户端密钥(PSCK)发送到客户端
  3. 在登录(或身份验证)以外的所有请求中,客户端将发送PSCK以防止用户名和密码被盗,服务器可以定期在内部验证PSCK到期,从而节省处理时间。
  4. 如果系统在身份验证方面存在性能问题,请设置具有可伸缩性的auth服务器。
  5. 没有令牌或密码被缓存,未加密交换并发送到安全区域外。不要使用URL参数发布。