Spring Security - Principal from Authorization Server is different from Resource Server(来自授权服务器的Spring Security-主体与资源服务器不同)
问题描述
我在授权服务器中创建了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
的值不同。其取值相当于上述principal.username
,省略了其他字段:
{
"userAuthentication": {
...
"principal": "xyz",
...
"name": "xyz"
},
...
"principal": "xyz",
...
"name": "xyz"
}
这是如何发生的?
我需要获取id
的值,但它不见了。principal
对象的字段已消失。这会导致我的其他方法出错:
@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'
请帮帮忙。谢谢。
推荐答案
可能很晚了,但这是我的解决方案。 因为我在我的资源服务器中使用了UserInfoTokenServices,所以我发现它使用了FixedEpalExtractor,在这个类中我看到了以下内容:
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;
}
所以它直接返回应用程序中的‘USER’值‘xyz’。 因此,我创建了一个类来实现ArchalExtractor,并重写他俩的方法:
import java.util.Map;
import org.springframework.boot.autoconfigure.security.oauth2.resource.PrincipalExtractor;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;
import com.project.LoginUser;
@Component
public class CustomPrincipalExtractor implements PrincipalExtractor {
@Override
@SuppressWarnings("unchecked")
public Object extractPrincipal(Map<String, Object> map) {
Map<String, Object> principal = (Map<String, Object>) map.get("principal");
return JSON.parseObject(JSON.toJSONString(principal), LoginUser.class);
}
}
此处的参数映射类似于授权服务器中的主体,因此我的LoginUser类具有‘main’键,它实现了UserDetail,并添加了一些附加信息,如id、电子邮件...就像你的校长一样。在这里,我使用fast json来解析它,您也可以使用ObjectMapper。 然后在您的资源服务器中定义UserInfoTokenServices Bean。以下是我的代码:
@EnableResourceServer
@EnableWebSecurity
@RequiredArgsConstructor
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
private final ResourceServerProperties sso;
private final CustomPrincipalExtractor customPrincipalExtractor;
@Primary
@Bean
public UserInfoTokenServices tokenService() {
UserInfoTokenServices userInfoTokenServices = new UserInfoTokenServices(sso.getUserInfoUri(), sso.getClientId());
userInfoTokenServices.setPrincipalExtractor(customPrincipalExtractor);
return userInfoTokenServices;
}
@Override
public void configure(HttpSecurity http) throws Exception {
...
}
}
在这里,我创建了UserInfoTokenServices,并设置了我的自定义ArchalExtractor。不要忘记添加这些属性:
security.oauth2.resource.user-info-uri = http://domain:port/your/user-info-url
security.oauth2.resource.prefer-token-info = false
现在您可以在资源服务器中获取您自己的主体对象。
这篇关于来自授权服务器的Spring Security-主体与资源服务器不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:来自授权服务器的Spring Security-主体与资源服务器不同
- 转换 ldap 日期 2022-01-01
- 将 Java Swing 桌面应用程序国际化的最佳实践是什么? 2022-01-01
- 未找到/usr/local/lib 中的库 2022-01-01
- GC_FOR_ALLOC 是否更“严重"?在调查内存使用情况时? 2022-01-01
- 如何指定 CORS 的响应标头? 2022-01-01
- 在 Java 中,如何将 String 转换为 char 或将 char 转换 2022-01-01
- java.lang.IllegalStateException:Bean 名称“类别"的 BindingResult 和普通目标对象都不能用作请求属性 2022-01-01
- 如何使 JFrame 背景和 JPanel 透明且仅显示图像 2022-01-01
- 获取数字的最后一位 2022-01-01
- Eclipse 的最佳 XML 编辑器 2022-01-01