I am writing a REST client in Java using the HttpCLient , the REST API that I access needs an auth token for every REST action. This token is valid for 24 hours.
我正在使用HttpCLient在Java中编写一个REST客户机,我访问的REST API对每个REST操作都需要一个auth令牌。这个令牌24小时有效。
The way I am handling this now is calling a "getAuth()
" method everytime I need to make a REST call which seems like an overhead on the auth server.
我现在处理这个问题的方式是每次需要进行REST调用时都调用“getAuth()”方法,这似乎是auth服务器上的开销。
How can I conveniently store this auth token and manage its life cycle? Are there any documented best practices?
如何方便地存储这个auth令牌并管理它的生命周期?是否有记录在案的最佳实践?
I thought of the following solution
我想到了下面的解决办法
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
}
}
and then pass the sessions object to any class that nees the token. If the token is expired, just call this method again
然后将session对象传递给任何需要令牌的类。如果令牌过期,请再次调用此方法。
3
I'm assuming you are using OAuth for authorization. Whether you are using JWT or other tokens is irrelevant to this situation.
我假设你是在使用OAuth进行授权。无论您是使用JWT还是其他令牌,都与这种情况无关。
When performing authorization you will be issued an access_token
with an expiration and, depending on the grant type you are requesting (Client credentials, Authorization code, Implicit, Resource owner), a refresh_token
.
当执行授权时,将向您颁发一个具有过期的access_token,根据您所请求的授予类型(客户端凭证、授权代码、隐式、资源所有者),一个refresh_token。
The client should keep the access_token
and the expiration. The refresh_token, if issued, must be kept secret (beware of using the correct grant for your use case).
客户端应该保留access_token和过期。如果发出refresh_token,则必须保密(注意不要对您的用例使用正确的grant)。
In subsequent calls, your client should not request new tokens on each call, it should use the stored access_token
.
在后续调用中,客户端不应该在每次调用中请求新的令牌,它应该使用存储的access_token。
Once the API starts returning 401 Unauthorized
, the access_token
has probably expired. Your client should try to refresh the access_token
using the refresh_token
if you got one.
一旦API开始返回401未授权,access_token可能已经过期。如果得到refresh_token,客户端应该尝试使用它刷新access_token。
If you have no refresh_token
or the refresh request also failed, because the refresh_token
is no longer valid, you can perform a new authorization flow.
如果没有refresh_token或refresh请求也失败,因为refresh_token不再有效,您可以执行一个新的授权流。
You can use the expiration time as a clue to know when to get a new access_token
either through refresh or through a new full authorization flow. This will avoid the 401 Unauthorized
. In any case, your client should have a fall back policy when this response is received after having used a valid access_token
for some calls.
您可以使用过期时间作为线索,以了解何时通过刷新或通过新的完整授权流获取新的access_token。这将避免401未经授权。无论如何,在使用有效的access_token进行一些调用之后,您的客户端应该有一个回退策略。
3
I suggest you to use the following scenario:
我建议你使用以下场景:
1) First, call auth(username, password)
rest api to get the auth token. If the given credentials are okay then just send back the auth COOKIE to the client with HTTP 200 response code.
首先,调用auth(用户名、密码)rest api获取auth令牌。如果给定的凭据是ok的,那么只需使用HTTP 200响应代码将auth COOKIE发送回客户机。
2) Then, you can call protected rest apis. You need to send auth COOKIE with your request each time.
然后,您可以调用protected rest api。每次都需要发送带有请求的auth COOKIE。
3) Servlet filter (or something similar) checks each incoming request and validates the token. If the token is valid then the request goes forward to the rest method, if not you need to generate an http 401/403 response.
Servlet过滤器(或类似的东西)检查每个传入请求并验证令牌。如果令牌是有效的,那么请求将转到rest方法,如果不是,则需要生成http 401/403响应。
I suggest you not to write your own authentication layer. Instead of install and use an existing one. I suggest you OpenAM. It is a superb open source access management system.
我建议您不要编写自己的身份验证层。而不是安装和使用一个现有的。我建议你OpenAM。这是一个优秀的开源访问管理系统。
I also suggest you not to open session on the server side for authentication purpose. If you have 10 clients then 10 sessions needs to be managed by server. It is not a big issue. But if you have 100 or 1000 or millions different clients than you need more memory to store sessions on the server.
我还建议您不要为了验证目的而在服务器端打开会话。如果您有10个客户端,那么需要服务器管理10个会话。这不是什么大问题。但是如果您有100或1000或上百万个不同的客户机,那么您就需要更多的内存来存储服务器上的会话。
2
The de-facto standard is not implementing your own solution (basic rule in security: don't implement your own stuff!), but use the de-facto standard solution, namely JSON Web Tokens.
事实上的标准不是实现您自己的解决方案(安全方面的基本规则:不要实现您自己的东西!),而是使用事实上的标准解决方案,即JSON Web令牌。
Documentation on the site, but the basic idea is, that you only need to store one value (the server's private key), and then you can verify every claim, issued originally by the server (which will in your case contain an expiry time).
站点上的文档,但基本思想是,您只需要存储一个值(服务器的私钥),然后您可以验证最初由服务器发出的每个索赔(在您的情况下,该请求包含一个过期时间)。
2
For brevity I'll assuming you're calling an endpoint that you can't change. How you should implement will heavily depend on whether the token is app or user based (one token for all users on a shared app instance or one token per user).
为了简便起见,我假设您调用了一个不能更改的端点。如何实现将在很大程度上取决于令牌是基于应用程序还是基于用户的(共享应用实例上的所有用户的一个令牌或每个用户的一个令牌)。
If it's one auth token for the entire app:
如果它是整个app的一个auth令牌:
If it's one token per user:
如果是每个用户一个令牌:
2
You should use JsonWebToken (JWT in short) for this kind of stuff. JWT has build in support to set the expiration date. There are plenty of libraries to use this method and you can read more here
对于这种东西,您应该使用JsonWebToken(简称JWT)。JWT已经建立了支持来设置过期日期。有很多库可以使用这个方法,您可以在这里阅读更多
There are currenlty 4 java implementations and all of them can check if the token is still valid (exp check)
有currenlty 4 java实现,它们都可以检查标记是否仍然有效(exp检查)
2
So if I'm understanding correctly you are using the same token for all of your requests (which means as long as your app is up and running and you refreshing the tokens, you should be ok. I literally had the same problem and this is how I've resolved it. I have a singleton class, which is initialized at the app start for once and refreshes the token when its invalidated. I'm using C#, Asp.NET MVC5 and AutoFac for DI, but I'm sure you can do the same with Java and Spring.
因此,如果我理解正确的话,您对所有请求都使用了相同的令牌(这意味着只要您的应用程序启动并运行并刷新令牌,您应该没有问题。我确实遇到了同样的问题,这就是我解决问题的方法。我有一个单例类,它在应用程序启动时初始化一次,在令牌失效时刷新令牌。我使用c#,Asp。NET MVC5和DI的AutoFac,但是我确信Java和Spring也可以做到这一点。
Updating property of a singleton with Thread Safety
具有线程安全性的单例对象的更新属性
2
You can create a manager and store the auth-COOKIE during login in thread local like the code below. You can get the COOKIE from getAuth()
as long as the thread lives.
您可以创建一个管理器,并在登录时将authCOOKIE存储在线程本地,如下面的代码所示。只要线程存在,就可以从getAuth()获取COOKIE。
public class Manager {
private static final ThreadLocal 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();
}
}
2
If you are worried about too many hits to the database, then i'm assuming there is a lot of web activity.
如果您担心数据库的点击率过高,那么我假设有很多web活动。
I would not recommend using Session in your case, but rather store the token in a COOKIE on the client.
我不建议在您的案例中使用会话,而是将标记存储在客户机的COOKIE中。
In a high traffic environment(which i'm assuming yours is), the use of Session can consume a lot of server memory, and scalability can be a concern as well, having to keep sessions in sync within a cluster.
在高通信量的环境中(我假设您的环境也是如此),会话的使用可能会消耗大量服务器内存,而且还需要考虑可伸缩性,必须在集群中保持会话的同步。
As @Cássio Mazzochi Molin also mentioned, you can use an in-memory cache to store any user specific data and tokens. This will reduce the hits to the database, and also allow you to scale the application easier, when the need arises.
正如@Cassio Mazzochi Molin也提到的,您可以使用内存缓存来存储任何用户特定的数据和令牌。这将减少对数据库的访问,并允许您在需要时更容易地扩展应用程序。
0
Use json web tokens , to exchange information between two clients. The token will only alive for the 24 hours period, after that time all consequent calls in the header will be rejected.
使用json web令牌在两个客户机之间交换信息。该令牌只在24小时内有效,之后,头中的所有后续调用都将被拒绝。
-1