如何从 OAuth2 授权服务器/用户端点获取自定义用户信息

新手上路,请多包涵

我有一个配置了 @EnableResourceServer 注释的资源服务器,它通过 user-info-uri 参数引用授权服务器,如下所示:

 security:
  oauth2:
    resource:
      user-info-uri: http://localhost:9001/user

授权服务器/用户端点返回 org.springframework.security.core.userdetails.User 的扩展名,其中包含例如电子邮件:

 {
   "password":null,
   "username":"myuser",
    ...
   "email":"me@company.com"
}

每当访问某个资源服务器端点时,Spring 通过调用授权服务器的 /user 端点来验证幕后的访问令牌,它实际上取回了丰富的用户信息(其中包含例如电子邮件信息,我已经用线鲨)。

所以问题是如何在没有明确第二次调用授权服务器的 /user 端点的情况下获取此自定义用户信息。 Spring 是否在授权后将其存储在资源服务器本地的某个位置,或者如果没有开箱即用的可用信息,实现这种用户信息存储的最佳方法是什么?

原文由 S. Pauk 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.3k
2 个回答

解决方案是自定义实现 UserInfoTokenServices

https://github.com/spring-projects/spring-boot/blob/master/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/UserInfoTokenServices.java

只需将您的自定义实现作为 Bean 提供,它将被使用而不是默认实现。

在这个 UserInfoTokenServices 中,您可以根据需要构建 principal

此 UserInfoTokenServices 用于从授权服务器的 /users 端点的响应中提取 UserDetails。如您所见

private Object getPrincipal(Map<String, Object> map) {
    for (String key : PRINCIPAL_KEYS) {
        if (map.containsKey(key)) {
            return map.get(key);
        }
    }
    return "unknown";
}

默认只提取 PRINCIPAL_KEYS 中指定的属性。这正是你的问题。您必须提取的不仅仅是用户名或您的属性名称。所以寻找更多的钥匙。

 private Object getPrincipal(Map<String, Object> map) {
    MyUserDetails myUserDetails = new myUserDetails();
    for (String key : PRINCIPAL_KEYS) {
        if (map.containsKey(key)) {
            myUserDetails.setUserName(map.get(key));
        }
    }
    if( map.containsKey("email") {
        myUserDetails.setEmail(map.get("email"));
    }
    //and so on..
    return myUserDetails;
}

接线:

 @Autowired
private ResourceServerProperties sso;

@Bean
public ResourceServerTokenServices myUserInfoTokenServices() {
    return new MyUserInfoTokenServices(sso.getUserInfoUri(), sso.getClientId());
}

!!使用 Spring Boot 1.4 更新事情变得更容易了!!

Spring Boot 1.4.0 引入了 PrincipalExtractor 。应该实现此类以提取自定义主体(请参阅 Spring Boot 1.4 发行说明)。

原文由 Yannic Bürgmann 发布,翻译遵循 CC BY-SA 3.0 许可协议

您可以使用 JWT 令牌。您不需要存储所有用户信息的数据存储区,而是可以将其他信息编码到令牌本身中。解码令牌后,您的应用程序将能够使用 Principal 对象访问所有这些信息

原文由 vladsfl 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题