我使用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对象传递给任何需要该令牌的类。如果令牌已过期,请再次调用此方法
答案 0 :(得分:7)
为简洁起见,我假设您正在调用一个无法更改的端点。您应该如何实现将在很大程度上取决于令牌是基于应用还是基于用户(共享应用实例上的所有用户一个令牌或每个用户一个令牌)。
如果它是整个应用程序的一个身份验证令牌:
如果每个用户只有一个令牌:
答案 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
答案 7 :(得分:2)
因此,如果我正确理解您正在为所有请求使用相同的令牌(这意味着只要您的应用启动并运行并且您刷新令牌,那么您应该没问题。我确实同样的问题,这就是我解决它的方法。我有一个单例类,它在应用程序启动时初始化一次,并在令牌失效时刷新令牌。我使用C#,Asp.NET MVC5和用于DI的AutoFac,但我确信你可以用Java和Spring做同样的事情。
答案 8 :(得分:0)
使用json web令牌,在两个客户端之间交换信息。该令牌仅在24小时内保持活动状态,此后标题中的所有后续呼叫都将被拒绝。
答案 9 :(得分:-1)