【问题标题】:Extend Micronaut CustomJWTClaimsSetGenerator to provide all attributes扩展 Micronaut CustomJWTClaimsSetGenerator 以提供所有属性
【发布时间】:2021-12-24 15:37:34
【问题描述】:

我有以下两个提供 JWT 身份验证机制的类。

CustomDelegatingAuthenticationProvider

@Singleton
@Replaces(value = DelegatingAuthenticationProvider.class)
public class CustomDelegatingAuthenticationProvider extends DelegatingAuthenticationProvider {
    /**
     * @param userFetcher        Fetches users from persistence
     * @param passwordEncoder    Collaborator which checks if a raw password matches an encoded password
     * @param authoritiesFetcher Fetches authorities for a particular user
     */
    public CustomDelegatingAuthenticationProvider(UserFetcher userFetcher, PasswordEncoder passwordEncoder, AuthoritiesFetcher authoritiesFetcher) {
        super(userFetcher, passwordEncoder, authoritiesFetcher);
    }

    @Override
    protected Publisher<AuthenticationResponse> createSuccessfulAuthenticationResponse(AuthenticationRequest authenticationRequest, UserState userState) {

        if (userState instanceof UserMember) {
            UserMember user = (UserMember) userState;
            return Flowable
                    .fromPublisher(authoritiesFetcher.findAuthoritiesByUsername(user.getUsername()))
                    .map(authorities -> new HDSUser(user.getUsername(), authorities, user.getId()));
        }
        return super.createSuccessfulAuthenticationResponse(authenticationRequest, userState);
    }
}

CustomJWTClaimsSetGenerator

@Singleton
@Replaces(value = JWTClaimsSetGenerator.class)
public class CustomJWTClaimsSetGenerator extends JWTClaimsSetGenerator {

    CustomJWTClaimsSetGenerator(TokenConfiguration tokenConfiguration, @Nullable JwtIdGenerator jwtIdGenerator, @Nullable ClaimsAudienceProvider claimsAudienceProvider) {
        super(tokenConfiguration, jwtIdGenerator, claimsAudienceProvider);
    }

    protected void populateWithUserDetails(JWTClaimsSet.Builder builder, UserDetails userDetails) {
        super.populateWithUserDetails(builder, userDetails);

        if (userDetails instanceof HDSUser) {
            builder.claim("userId", ((HDSUser) userDetails).getId());
        }
    }

}

对客户端的默认响应如下所示:

我的问题。如何扩展类以返回所有用户属性?除了用户名之外,我还想拥有用户 ID。

更新

收集 DB id 的 HDS 用户类

@CompileStatic
public class HDSUser  extends UserDetails {

    private long id;

    public HDSUser(String username, Collection<String> roles, long id) {
        super(username, roles);
        this.id = id;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }
}

【问题讨论】:

  • 只是在黑暗中拍摄,但 userDetails 可能不是instanceof HDSUser

标签: java authentication jwt micronaut


【解决方案1】:

要扩展返回的数据,您需要扩展(实现自定义)TokenRenderer 以及 AccessRefreshToken 的自定义版本。 作为一个简单的示例,请参见以下代码片段,它将使用 userId 字段扩展默认访问令牌有效负载。

首先,创建一个自定义 AccessRefreshToken 类,其中包含必需的附加字段。

@Introspected
@Getter
@Setter
public class CustomAccessRefreshToken extends BearerAccessRefreshToken {
    
    // the new field which will be in the response
    private String userId;

    public CustomAccessRefreshToken(String username,
                                Collection<String> roles,
                                Integer expiresIn,
                                String accessToken,
                                String refreshToken,
                                String tokenType
    ) {
        super(username, roles, expiresIn, accessToken, refreshToken, tokenType);
    }
  
}

接下来,我们需要一个TokenRenderer,底层子系统将使用它来生成我们的自定义令牌。

@Singleton
@Replaces(value = BearerTokenRenderer.class)
public class CustomTokenRenderer implements TokenRenderer {
    private static final String BEARER_TOKEN_TYPE = HttpHeaderValues.AUTHORIZATION_PREFIX_BEARER;

    @Override
    public AccessRefreshToken render(Integer expiresIn, String accessToken, @Nullable String refreshToken) {
    return new AccessRefreshToken(accessToken, refreshToken, BEARER_TOKEN_TYPE, expiresIn);
    }

    @Override
    public AccessRefreshToken render(Authentication authentication, Integer expiresIn, String accessToken, @Nullable String refreshToken) {
        CustomAccessRefreshToken token =  new CustomAccessRefreshToken(authentication.getName(), authentication.getRoles(), expiresIn, accessToken, refreshToken, BEARER_TOKEN_TYPE);
        // here just take the user data from Authentication object or access any other service
        token.setUserId("Some user id");
        return token;
    }
}

就是这样 )) 只需按照您想要的方式实现 render() 方法并根据需要添加任意数量的自定义字段。

给定示例的响​​应将如下所示

{
    "username": "sherlock",
    "userId": "Some user id",
    "access_token": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzaGVybG9jayIsIm5iZiI6MTYzNjk5MTgzMSwicm9sZXMiOltdLCJpc3MiOiJtaWNyb25hdXRndWlkZSIsImV4cCI6MTYzNjk5NTQzMSwiaWF0IjoxNjM2OTkxODMxfQ.Cat1CTsUZkCj-OHGafiefNm1snPsALoaNw9y2xwF5Pw",
    "token_type": "Bearer",
    "expires_in": 3600
}

如果您使用的是旧版本的 Micronaut v1.x,TokenRenderer 将如下所示。

@Singleton
@Replaces(value = BearerTokenRenderer.class)
public class CustomTokenRenderer implements TokenRenderer {
    private static final String BEARER_TOKEN_TYPE = HttpHeaderValues.AUTHORIZATION_PREFIX_BEARER;

    public AccessRefreshToken render(Integer expiresIn, String accessToken, String refreshToken) {
        return new AccessRefreshToken(accessToken, refreshToken, BEARER_TOKEN_TYPE, expiresIn);
    }

    public AccessRefreshToken render(UserDetails userDetails, Integer expiresIn, String accessToken, String refreshToken) {
        CustomAccessRefreshToken token =  new CustomAccessRefreshToken(userDetails.getUsername(), userDetails.getRoles(), expiresIn, accessToken, refreshToken, BEARER_TOKEN_TYPE);
        token.setUserId("Some user id, Some user id");
        return token;
    }
}

【讨论】:

  • 感谢您的回答,但我如何管理我的端点以达到这些课程?
  • 无需管理任何东西,系统已配置为可以访问它们。如果您处于身份验证:承载模式并且有人将正确的用户名/密码对发布到 /login 端点,则将执行代码。
  • 好的,我会尝试...我只是对一些注释有一些问题。您还可以添加导入吗?
  • 我使用的是lombok,如果你不使用它只需删除@Getter@Setter并手动实现getter和setter
  • CustomTokenRenderer 需要两种不同的渲染方法..?
猜你喜欢
  • 1970-01-01
  • 2014-10-20
  • 1970-01-01
  • 2011-09-05
  • 1970-01-01
  • 2021-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多