gpt4 book ai didi

java - 如何扩展 OAuth2 主体

转载 作者:行者123 更新时间:2023-12-04 16:06:14 26 4
gpt4 key购买 nike

我们正在开发一个将 OAuth 2 用于两个用例的应用程序:

  • 访问后端微服务(使用 client_credentials)
  • 验证应用程序的用户(使用 authorization_code ,因此将用户重定向到 Keycloak 进行登录,大致配置如 tutorial 所示)。

  • 在对我们的用户进行身份验证时,我们从身份验证服务器接收部分信息(例如登录),另一部分可以在本地用户表中找到。我们喜欢做的是创建一个 Principal 对象,其中还包含来自本地数据库的数据。

    PrincipalExtractor好像是 the way to go .由于我们必须使用手动 OAuth 配置来不干扰 OAuth 用例 1,因此我们创建并设置它:
    tokenServices.setPrincipalExtractor(ourPrincipalExtractor);

    该实现基本上执行数据库查找并在映射函数中返回一个 CustomUser 对象。现在虽然这似乎有效(调用了提取器),但它并没有正确地保留在 session 中。因此,在我们的许多 REST 资源中,我们注入(inject)了当前用户:
    someRequestHandler(@AuthenticationPrincipal CustomUser activeUser) {

    并在那里接收空值。查看注入(inject)的 Authentication它表明它是一个 OAuth2Authentication具有默认 Principal 对象的对象(我认为它是 Spring User/ UserDetails )。所以 null 因为它不是我们的 CustomUser之前返回。

    是不是我们误会了 PrincipalExtractor作品?是否可能是我们的过滤器链配置错误,因为我们在同一个应用程序中有两种不同的 OAuth 机制,如前所述? Spring 的 Principal 存储库中的断点向我们展示了 CustomUser保存在那里,然后用原始类型保存,似乎覆盖它。

    最佳答案

    我可以告诉你我是如何使用 JWT 做类似的事情的。如果您不使用 JWT,那么我不确定这是否会有所帮助。

    我有一个非常相似的问题,因为我注入(inject)的主体只包含用户名。不像你的那样空,但显然不是我想要的。我最终做的是扩展 TokenEnhancerJwtAccessTokenConverter .

    我使用 TokenEnhancer嵌入我的 CustomUserDetails 类型的扩展主体JWT 中的附加信息。

    public class CustomAccessTokenEnhancer implements TokenEnhancer {

    @Override
    public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
    Authentication userAuthentication = authentication.getUserAuthentication();
    if (userAuthentication != null) {
    Object principal = authentication.getUserAuthentication().getPrincipal();
    if (principal instanceof CustomUserDetails) {
    Map<String, Object> additionalInfo = new HashMap<>();
    additionalInfo.put("userDetails", principal);
    ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
    }
    }
    return accessToken;
    }
    }

    然后在构建 Authentication时手动提取扩展主体处理经过身份验证的请求时的对象。
    public class CustomJwtAccessTokenConverter extends JwtAccessTokenConverter {

    @Override
    public OAuth2Authentication extractAuthentication(Map<String, ?> map) {
    OAuth2Authentication authentication = super.extractAuthentication(map);
    Authentication userAuthentication = authentication.getUserAuthentication();

    if (userAuthentication != null) {
    LinkedHashMap userDetails = (LinkedHashMap) map.get("userDetails");
    if (userDetails != null) {

    // build your extended principal here
    String localUserTableField = (String) userDetails.get("localUserTableField");
    CustomUserDetails extendedPrincipal = new CustomUserDetails(localUserTableField);

    Collection<? extends GrantedAuthority> authorities = userAuthentication.getAuthorities();

    userAuthentication = new UsernamePasswordAuthenticationToken(extendedPrincipal,
    userAuthentication.getCredentials(), authorities);
    }
    }
    return new OAuth2Authentication(authentication.getOAuth2Request(), userAuthentication);
    }
    }

    AuthorizationServer配置将它们联系在一起。
    @Configuration
    @EnableAuthorizationServer
    public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private DataSource dataSource;

    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
    CustomJwtAccessTokenConverter accessTokenConverter = new CustomJwtAccessTokenConverter();
    accessTokenConverter.setSigningKey("a1b2c3d4e5f6g");
    return accessTokenConverter;
    }

    @Bean
    public TokenStore tokenStore() {
    return new JwtTokenStore(accessTokenConverter());
    }

    @Bean
    @Primary
    public DefaultTokenServices tokenServices() {
    DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
    defaultTokenServices.setTokenStore(tokenStore());
    defaultTokenServices.setSupportRefreshToken(true);
    return defaultTokenServices;
    }

    @Bean
    public TokenEnhancer tokenEnhancer() {
    return new CustomAccessTokenEnhancer();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    clients.jdbc(dataSource).passwordEncoder(passwordEncoder());
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
    tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer(), accessTokenConverter()));
    endpoints
    .tokenStore(tokenStore())
    .tokenEnhancer(tokenEnhancerChain)
    .authenticationManager(authenticationManager)
    .userDetailsService(userDetailsService);
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
    security.passwordEncoder(passwordEncoder());
    security.checkTokenAccess("isAuthenticated()");
    }
    }

    然后我就可以像这样在我的资源 Controller 中访问我的扩展主体
    @RestController
    public class SomeResourceController {

    @RequestMapping("/some-resource")
    public ResponseEntity<?> someResource(Authentication authentication) {
    CustomUserDetails userDetails = (CustomUserDetails) authentication.getPrincipal();
    return ResponseEntity.ok("woo hoo!");
    }

    }

    关于java - 如何扩展 OAuth2 主体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48708406/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com