实施 Spring OAuth2,从不同设备获取相同的访问令牌
Implemented Spring OAuth2, getting same access token from different devices
实现了 SpringOAuth2 安全性并在使用同一用户但从不同设备登录时获得相同的访问令牌。当我从这些设备中的任何一个注销(撤销令牌)时,其他设备也会被注销。这是预期的行为还是我遗漏了什么?希望共享大量代码不会有太大帮助,所以让问题简短。
The default behaviour of the DefaultTokenServices is to re-use existing tokens (based on the behaviour of the existing TokenStore implementations)
如果您希望每个设备都被赋予不同的 access_token
然后创建您自己的 AuthenticationKeyGenerator
例如在授权过程中发送您的设备 ID,并让您的 AuthenticationKeyGenerator
处理该设备 ID 以创建 access_token
特定于该设备。
遇到同样问题的可以参考MangEngkus回复的解决方案,具体解决方案也可以参考这个link Spring OAuth2 Generate Access Token per request to the Token Endpoint
(请阅读 org.springframework.security.oauth2.provider.token.DefaultAuthenticationKeyGenerator
代码以将以下解决方案放入上下文中)
DefaultAuthenticationKeyGenerator
在 spring 可用。我刚刚创建了一个具有相同代码和一个扩展名的自定义版本,即从客户端发送的 device_id
作为请求参数是从 OAuth2Authentication
中检索的,如下所示;
String deviceId = authentication.getOAuth2Request().getRequestParameters().get("device_id")
然后被放入values
映射中(用于最终生成token)。因此 device_id
成为 token
的一部分,导致每个设备都有一个唯一的令牌。
以下是完整的解决方案,除了上面解释的位之外,主要是DefaultAuthenticationKeyGenerator
。
public class CustomAuthenticationKeyGenerator implements AuthenticationKeyGenerator
{
private static final String CLIENT_ID = "client_id";
private static final String SCOPE = "scope";
private static final String USERNAME = "username";
@Override
public String extractKey(OAuth2Authentication authentication) {
Map<String, String> values = new LinkedHashMap<String, String>();
OAuth2Request authorizationRequest = authentication.getOAuth2Request();
if (!authentication.isClientOnly()) {
values.put(USERNAME, authentication.getName());
}
values.put(CLIENT_ID, authorizationRequest.getClientId());
if (authorizationRequest.getScope() != null) {
values.put(SCOPE, OAuth2Utils.formatParameterList(authorizationRequest.getScope()));
}
String deviceId = authorizationRequest.getRequestParameters().get(CustomHeader.device_id.name());
if(deviceId != null && !deviceId.isEmpty()) {
values.put("device_id", deviceId);
}
MessageDigest digest;
try {
digest = MessageDigest.getInstance("MD5");
}
catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("MD5 algorithm not available. Fatal (should be in the JDK).");
}
try {
byte[] bytes = digest.digest(values.toString().getBytes("UTF-8"));
return String.format("%032x", new BigInteger(1, bytes));
}
catch (UnsupportedEncodingException e) {
throw new IllegalStateException("UTF-8 encoding not available. Fatal (should be in the JDK).");
}
}
}
实现了 SpringOAuth2 安全性并在使用同一用户但从不同设备登录时获得相同的访问令牌。当我从这些设备中的任何一个注销(撤销令牌)时,其他设备也会被注销。这是预期的行为还是我遗漏了什么?希望共享大量代码不会有太大帮助,所以让问题简短。
The default behaviour of the DefaultTokenServices is to re-use existing tokens (based on the behaviour of the existing TokenStore implementations)
如果您希望每个设备都被赋予不同的 access_token
然后创建您自己的 AuthenticationKeyGenerator
例如在授权过程中发送您的设备 ID,并让您的 AuthenticationKeyGenerator
处理该设备 ID 以创建 access_token
特定于该设备。
遇到同样问题的可以参考MangEngkus回复的解决方案,具体解决方案也可以参考这个link Spring OAuth2 Generate Access Token per request to the Token Endpoint
(请阅读 org.springframework.security.oauth2.provider.token.DefaultAuthenticationKeyGenerator
代码以将以下解决方案放入上下文中)
DefaultAuthenticationKeyGenerator
在 spring 可用。我刚刚创建了一个具有相同代码和一个扩展名的自定义版本,即从客户端发送的 device_id
作为请求参数是从 OAuth2Authentication
中检索的,如下所示;
String deviceId = authentication.getOAuth2Request().getRequestParameters().get("device_id")
然后被放入values
映射中(用于最终生成token)。因此 device_id
成为 token
的一部分,导致每个设备都有一个唯一的令牌。
以下是完整的解决方案,除了上面解释的位之外,主要是DefaultAuthenticationKeyGenerator
。
public class CustomAuthenticationKeyGenerator implements AuthenticationKeyGenerator
{
private static final String CLIENT_ID = "client_id";
private static final String SCOPE = "scope";
private static final String USERNAME = "username";
@Override
public String extractKey(OAuth2Authentication authentication) {
Map<String, String> values = new LinkedHashMap<String, String>();
OAuth2Request authorizationRequest = authentication.getOAuth2Request();
if (!authentication.isClientOnly()) {
values.put(USERNAME, authentication.getName());
}
values.put(CLIENT_ID, authorizationRequest.getClientId());
if (authorizationRequest.getScope() != null) {
values.put(SCOPE, OAuth2Utils.formatParameterList(authorizationRequest.getScope()));
}
String deviceId = authorizationRequest.getRequestParameters().get(CustomHeader.device_id.name());
if(deviceId != null && !deviceId.isEmpty()) {
values.put("device_id", deviceId);
}
MessageDigest digest;
try {
digest = MessageDigest.getInstance("MD5");
}
catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("MD5 algorithm not available. Fatal (should be in the JDK).");
}
try {
byte[] bytes = digest.digest(values.toString().getBytes("UTF-8"));
return String.format("%032x", new BigInteger(1, bytes));
}
catch (UnsupportedEncodingException e) {
throw new IllegalStateException("UTF-8 encoding not available. Fatal (should be in the JDK).");
}
}
}