在我的Java EE6,REST服务上,我想使用身份验证令牌从移动设备登录,用户将发送他们的用户名,密码和服务器将发回一个令牌,该令牌将用于授权用户进一步请求在给定的时间内。
我可以像这样简单地创建一个令牌吗?(我想我不需要加密它,因为我会使用HTTPS。)
String token = UUID.randomUUID().toString().toUpperCase()
+ "|" + "userid" + "|"
+ cal.getTimeInMillis();
或者有一种更独特的方式来创建我的令牌?也许它存在于API的一个
中答案 0 :(得分:14)
要在Java中创建难以猜测的令牌,请使用java.security.SecureRandom
E.g。
SecureRandom random = new SecureRandom();
byte bytes[] = new byte[20];
random.nextBytes(bytes);
String token = bytes.toString();
不是在令牌中包含用户名,而是在内存或数据库中缓存用户:令牌映射更好。
答案 1 :(得分:9)
您提出的方案实际上允许客户无限制地访问您的服务。初次登录后,UID和'userid'将可供客户端使用,可以简单地与始终有效的时间戳结合使用。
如果您需要具有“登录”和会话令牌的服务,那么为什么不使用HttpSession?
答案 2 :(得分:4)
对于Java 8及更高版本,最快,最简单的解决方案是:
private static final SecureRandom secureRandom = new SecureRandom(); //threadsafe
private static final Base64.Encoder base64Encoder = Base64.getUrlEncoder(); //threadsafe
public static String generateNewToken() {
byte[] randomBytes = new byte[24];
secureRandom.nextBytes(randomBytes);
return base64Encoder.encodeToString(randomBytes);
}
输出示例:
wrYl_zl_8dLXaZul7GcfpqmDqr7jEnli
7or_zct_ETxJnOa4ddaEzftNXbuvNSB-
CkZss7TdsTVHRHfqBMq_HqQUxBGCTgWj
8loHzi27gJTO1xTqTd9SkJGYP8rYlNQn
以上代码将以32个字符的base64编码生成随机字符串。在Base64编码中,每个char编码6位数据。因此,对于上述示例中的24个字节,您将获得32个字符。您可以通过更改随机字节数来更改输出字符串的长度。此解决方案比UUID
(仅使用16个随机字节)更安全,并生成可以在HTTP url中安全使用的字符串。
答案 3 :(得分:1)
public class SecureTokenGenerator {
public static final String CHARACTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
// 2048 bit keys should be secure until 2030 - https://web.archive.org/web/20170417095741/https://www.emc.com/emc-plus/rsa-labs/historical/twirl-and-rsa-key-size.htm
public static final int SECURE_TOKEN_LENGTH = 256;
private static final SecureRandom random = new SecureRandom();
private static final char[] symbols = CHARACTERS.toCharArray();
private static final char[] buf = new char[SECURE_TOKEN_LENGTH];
/**
* Generate the next secure random token in the series.
*/
public static String nextToken() {
for (int idx = 0; idx < buf.length; ++idx)
buf[idx] = symbols[random.nextInt(symbols.length)];
return new String(buf);
}
}
采取并显着缩小答案 4 :(得分:0)
REST基于HTTP,并鼓励使用底层协议而不是重新发明轮子。 HTTP使用cookie来支持有状态的交互,例如记住身份验证,还支持用户名和密码身份验证。
此外,Java EE支持所有这些开箱即用的功能。查看教程
答案 5 :(得分:0)
有一种创建令牌的方法,它既不会受到损害,也可以用于身份验证。
创建一个合并的令牌:
base64(用户名+过期+客户端+ 3des编码的其他值(使用名称,过期,源IP,浏览器标识符,客户端的其他值))
客户端可以使用令牌对请求进行身份验证,例如使用JSON Web令牌(RFC 7515)。
在服务器端,用于3des编码的密钥可以随时间旋转,作为令牌。每个请求都包含用于身份验证的令牌,并且每个响应在到期之前包含相同的令牌或新令牌。
在这种情况下,令牌包含用户名,因此在请求身份验证时只需要检查3des编码部分是否有效(与请求ip的源相同。在这种情况下,如果有人偷走了令牌的可用性令牌更受限制为会话ID。您可以将其他标识符组合成令牌,如浏览器等。更难以伪造请求,因为攻击者必须伪造更多东西 - 这对他来说是未知的,因为他不知道什么是令牌的编码部分。(事实上,没有完美的安全性,只能更难破解)
此解决方案的优点是:
缺点是
更难在服务器端实现,因为此解决方案必须在服务器端实现令牌生成/验证算法对于建议使用该服务器过滤器,。
客户必须实施令牌存储 - 建议不要使用cookie浏览器会话存储 - 更容易窃取cookie。
答案 6 :(得分:0)
创建一个唯一的令牌,它完全基于逻辑和您使用了多少个参数。 Java 8 的Supplier
功能界面可帮助您:
Supplier<String> tokenSupplier = () -> {
StringBuilder token = new StringBuilder();
long currentTimeInMilisecond = Instant.now().toEpochMilli();
return token.append(currentTimeInMilisecond).append("-")
.append(UUID.randomUUID().toString()).toString();
};
System.out.println(tokenSupplier.get());
输出:
1591457374665-d5eff25f-b083-41c3-a90d-a89adcc45043
您可以在此处了解更多信息-Java Token