Java Spring安全性-来自授权服务器的主体不同于资源服务器
我在授权服务器中创建了Java Spring安全性-来自授权服务器的主体不同于资源服务器,java,spring,spring-boot,spring-security,spring-security-oauth2,Java,Spring,Spring Boot,Spring Security,Spring Security Oauth2,我在授权服务器中创建了userinfo端点 @GetMapping("/userinfo") public Principal me(Principal principal) { return principal; } 它返回以下JSON: { ... "userAuthentication": { ... "principal": { "id": 2, "username": "xyz",
userinfo
端点
@GetMapping("/userinfo")
public Principal me(Principal principal) {
return principal;
}
它返回以下JSON:
{
...
"userAuthentication": {
...
"principal": {
"id": 2,
"username": "xyz",
"password": "......",
"accountNonExpired": true,
"accountNonLocked": true,
"credentialsNonExpired": true,
"enabled": true,
"authorities": [
{
"authority": "ROLE_DONOR"
}
],
"createdAt": "2019-11-08T20:50:46"
},
...
"name": "xyz"
},
...
"principal": {
"id": 2,
"username": "xyz",
"password": "......",
"accountNonExpired": true,
"accountNonLocked": true,
"credentialsNonExpired": true,
"enabled": true,
"authorities": [
{
"authority": "ROLE_DONOR"
}
],
"createdAt": "2019-11-08T20:50:46"
},
...
"name": "xyz"
}
在我的一个资源服务器用户服务API中,我试图sysout
查看Principal
的值,只是为了查看它的值:
@GetMapping("/{id}")
public ResourceResponseDto findById(@PathVariable("id") long id, Principal principal) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
String x = objectMapper.writeValueAsString(principal);
System.out.println(x);
return ...;
}
principal
的值不同。它的值等于上面的主体.username
,省略了其他字段:
{
"userAuthentication": {
...
"principal": "xyz",
...
"name": "xyz"
},
...
"principal": "xyz",
...
"name": "xyz"
}
这是怎么发生的
我需要得到id
的值,但它已经不存在了。principal
object的字段消失了。这会导致我的另一种方法出现错误:
@GetMapping("/{id}")
@PreAuthorize("hasRole('ADMIN') or #id == principal.id")
public ResourceResponseDto findById(@PathVariable("id") long id) {
//
}
我得到了这个错误
Failed to evaluate expression 'hasRole('ADMIN') or #id == principal.id'
请帮忙。谢谢。据我所知,您正在实现OAuth2 Spring身份验证服务器。
Principle
只是一个声明方法getName()
的接口。对于身份验证和资源服务器,原则
由类OAuth2Authentication
实现。方法getPrinciple()
:
如果OAuth2客户端正在进行身份验证,则它没有
userAuthentication
,只有clientId
。如果用户正在进行身份验证,您将看到完整的userAuthentication
对象。据我所知,您正在实现OAuth2 Spring身份验证服务器。
Principle
只是一个声明方法getName()
的接口。对于身份验证和资源服务器,原则
由类OAuth2Authentication
实现。方法getPrinciple()
:
如果OAuth2客户端正在进行身份验证,则它没有
userAuthentication
,只有clientId
。如果用户正在进行身份验证,则可以从Authentication.getPrincipal()
文档中看到完整的userAuthentication
对象。:
正在进行身份验证的主体的标识。对于使用用户名和密码的身份验证请求,这将是用户名。调用者需要填充身份验证请求的主体。
AuthenticationManager实现通常会返回
身份验证包含更丰富的信息作为主体供用户使用
应用程序。许多身份验证提供程序将创建一个
UserDetails对象作为主体
因此,您负责在身份验证过程中填充主体
向主体
传递附加信息的方法之一是扩展用户名密码身份验证筛选器
并重写“attemptAuthentication()”方法:
请注意,将可能包含所需任何数据的YourObjectForPrincipal
对象作为第一个参数传递给UsernamePasswordAuthenticationToken
。
要获得扩展用户,只需强制转换到所需对象:
(YourObjectForPrincipal)authentication.getPrincipal();
这可能不是最好的解决方案,但对我来说很有效。
我希望这会有帮助 来自Authentication.getPrincipal()
文档:
正在进行身份验证的主体的标识。对于使用用户名和密码的身份验证请求,这将是用户名。调用者需要填充身份验证请求的主体。
AuthenticationManager实现通常会返回
身份验证包含更丰富的信息作为主体供用户使用
应用程序。许多身份验证提供程序将创建一个
UserDetails对象作为主体
因此,您负责在身份验证过程中填充主体
向主体
传递附加信息的方法之一是扩展用户名密码身份验证筛选器
并重写“attemptAuthentication()”方法:
请注意,将可能包含所需任何数据的YourObjectForPrincipal
对象作为第一个参数传递给UsernamePasswordAuthenticationToken
。
要获得扩展用户,只需强制转换到所需对象:
(YourObjectForPrincipal)authentication.getPrincipal();
这可能不是最好的解决方案,但对我来说很有效。
我希望这会有帮助 也许已经晚了,但这是我的解决办法。
由于我在我的资源服务器中使用了UserInfoTokenServices,我发现它使用了FixedPrincipalExtractor,在这个类中我看到:
private static final String[] PRINCIPAL_KEYS = new String[] { "user", "username",
"userid", "user_id", "login", "id", "name" };
@Override
public Object extractPrincipal(Map<String, Object> map) {
for (String key : PRINCIPAL_KEYS) {
if (map.containsKey(key)) {
return map.get(key);
}
}
return null;
}
在这里,我创建了一个UserInfoTokenServices,并设置了我的自定义。不要忘记添加以下属性:
security.oauth2.resource.user-info-uri = http://domain:port/your/user-info-url
security.oauth2.resource.prefer-token-info = false
现在,您可以在资源服务器中获得自己的主体对象。可能已经晚了,但这是我的解决方案。
由于我在我的资源服务器中使用了UserInfoTokenServices,我发现它使用了FixedPrincipalExtractor,在这个类中我看到:
private static final String[] PRINCIPAL_KEYS = new String[] { "user", "username",
"userid", "user_id", "login", "id", "name" };
@Override
public Object extractPrincipal(Map<String, Object> map) {
for (String key : PRINCIPAL_KEYS) {
if (map.containsKey(key)) {
return map.get(key);
}
}
return null;
}
在这里,我创建了一个UserInfoTokenServices,并设置了我的自定义。不要忘记添加以下属性:
security.oauth2.resource.user-info-uri = http://domain:port/your/user-info-url
security.oauth2.resource.prefer-token-info = false
现在,您可以在资源服务器中获得自己的主体对象。首先检查主体
在每种情况下是什么类。首先检查主体
在每种情况下是什么类。我会在授权服务器中实现这一点吗?而YourObjectForPrincipal
指的是我的对象,它包含id
,username
,等等,对吗?@Julez您可以在任意一侧添加它。对于资源服务器,您可以通过AuthorizationServerSecurityConfiger添加它。addTokenEndpointAuthenticationFilter()我创建了一个类,该类使用接受AuthenticationManager
实例的构造函数扩展UsernamePasswordAuthenticationFilter
。我将此.getAuthenticationManager()替换为此.authenticationManager。
。在我的身份验证服务器配置中,我有以下内容:authorizationServerSecurityConfiger.addTokenEndpointAuthenticationFilter(新的CustomUsernamePassw
security.oauth2.resource.user-info-uri = http://domain:port/your/user-info-url
security.oauth2.resource.prefer-token-info = false