java 管理身份验证令牌的最佳实践
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/42278683/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Best practices for managing auth token
提问by user_mda
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 操作提供一个身份验证令牌。此令牌的有效期为 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.
我现在处理这个问题的方式是getAuth()
每次我需要进行 REST 调用时调用一个“ ”方法,这似乎是身份验证服务器上的开销。
How can I conveniently store this auth token and manage its life cycle? Are there any documented best practices?
如何方便地存储此身份验证令牌并管理其生命周期?是否有任何记录在案的最佳实践?
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
然后将会话对象传递给任何需要令牌的类。如果令牌已过期,只需再次调用此方法
回答by Dave L
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:
如果它是整个应用程序的一个身份验证令牌:
- Store it in memory along with a time-to-live timestamp (or alternatively catch the token expired error, request a new token and retry the original request), refresh it if it doesn't exist/is expired
- If you're concerned about re-requesting API tokens after an application restart also store it in the database and load it at startup if it exists
- 将它与生存时间时间戳一起存储在内存中(或者捕获令牌过期错误,请求一个新令牌并重试原始请求),如果它不存在/已过期则刷新它
- 如果您担心在应用程序重新启动后重新请求 API 令牌,请将其存储在数据库中并在启动时加载(如果存在)
If it's one token per user:
如果是每个用户一个令牌:
- Store it in your user session, it's exactly what sessions are used for, if you're authing users then they'll have a session and the overhead is already there
- If you don't want to re-request a token everytime they login store their current token in the DB and and load it into their session when they login
- 将它存储在您的用户会话中,这正是会话的用途,如果您正在对用户进行身份验证,那么他们将有一个会话并且开销已经存在
- 如果您不想每次登录时都重新请求令牌,请将当前令牌存储在数据库中,并在登录时将其加载到会话中
回答by Daniel Cerecedo
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(如果发布)必须保密(注意为您的用例使用正确的授权)。
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 Unauthorized
,access_token
可能已经过期。你的客户端应该尝试刷新access_token
使用refresh_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_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 Unauthorized
. 在任何情况下,在access_token
对某些调用使用有效值后收到此响应时,您的客户端都应该有回退策略。
回答by grizzthedj
If you are worried about too many hits to the database, then i'm assuming there is a lot of web activity.
如果您担心对数据库的访问过多,那么我假设有很多网络活动。
I would not recommend using Session in your case, but rather store the token in a cookie on the client.
我不建议在您的情况下使用 Session,而是将令牌存储在客户端的 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.
在高流量环境中(我假设您的环境是这样),使用 Session 会消耗大量服务器内存,而且可伸缩性也是一个问题,必须在集群内保持会话同步。
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.
正如@Cássio Mazzochi Molin 也提到的,您可以使用内存缓存来存储任何用户特定的数据和令牌。这将减少对数据库的点击,并允许您在需要时更轻松地扩展应用程序。
回答by zappee
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.
1)首先调用auth(username, password)
rest api获取auth token。如果给定的凭据没问题,那么只需将带有 HTTP 200 响应代码的 auth cookie 发送回客户端。
2) Then, you can call protected rest apis. You need to send auth cookie with your request each time.
2)然后,您可以调用受保护的rest apis。您每次都需要随请求发送 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.
3) 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 或数百万个不同的客户端,那么您需要更多的内存来在服务器上存储会话。
回答by arjun sahasranam
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.
您可以创建一个管理器并在登录期间将 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();
}
}
回答by D. Kovács
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 Tokens。
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).
网站上的文档,但基本思想是,您只需要存储一个值(服务器的私钥),然后您就可以验证服务器最初发布的每个声明(在您的情况下,它将包含一个到期时间) .
回答by Murf
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)
回答by Mavi Domates
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 和 AutoFac 进行 DI,但我确定你可以用 Java 和 Spring 做同样的事情。
回答by Remario
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 tokens ,在两个客户端之间交换信息。令牌只会在 24 小时内存活,在那之后,标头中的所有后续调用都将被拒绝。
回答by SACn
- Auth Token for each request is correct approach, Consider auth server scaling for performance issue.
- On first successful authentication (username and password), generate private public keypair. Store private key as Session Security Token (SST)and send public key as Public Security Client Key (PSCK)to client
- In all request other than login (or authentication) client will send PSCK to protect theft of username and password and server can verify PSCK for expiry internally at regular intervals saving processing time.
- If system is having performance issue on authentication side, setup seperate auth server with scalability.
- No token or password to be cached, exchanged unencrypted and send outside security zone. Do not post using URL parameters.
- 每个请求的身份验证令牌是正确的方法,考虑性能问题的身份验证服务器扩展。
- 在第一次成功认证(用户名和密码)时,生成私有公钥对。将私钥存储为会话安全令牌 (SST)并将公钥作为公共安全客户端密钥 (PSCK)发送给客户端
- 在除登录(或身份验证)之外的所有请求中,客户端将发送 PSCK 以防止用户名和密码被盗,服务器可以定期在内部验证 PSCK 是否到期,从而节省处理时间。
- 如果系统在身份验证方面存在性能问题,请设置具有可扩展性的单独身份验证服务器。
- 没有令牌或密码被缓存、交换未加密和发送到安全区域之外。不要发布使用 URL 参数。