提供 JWT 时如何在 micronaut 后端加载 "user"

How do I load a "user" in a micronaut backend when JWT is provided

我有一个通过 JsonWebTokens (JWT) 处理身份验证的 Micronaut 微服务 from this guide

现在我想扩展这段代码。我的应用程序中的用户有一些额外的属性,如电子邮件、地址、teamId 等。我在数据库中有所有用户。

我怎么知道在后端控制器方法哪个用户对应客户端发送的JWT?

该指南包含 Micronaut REST 控制器的示例代码:

@Secured(SecurityRule.IS_AUTHENTICATED)
@Controller
public class HomeController {
    @Produces(MediaType.TEXT_PLAIN)
    @Get
    public String index(Principal principal) {
        return principal.getName();
    }
}

我知道我可以得到校长的名字,即。来自 HttpRequest 的用户名。但是如何获得我的附加属性?

(可能我对JWT有点误解???)


编辑 更详细地描述我的用例:

我的用例的安全要求

身份验证流程

带有 JWT 的默认 oauth2 流程:

前提条件:用户已经注册。后端已知用户名、哈希(密码)和其他属性(电子邮件、地址、teamId 等)。

  1. 客户端将用户名和密码发送到 /login 端点
  2. 客户端在 return 中接收 JWT,使用服务器密钥签名
  3. 在以后的每个请求中,客户端都会在 Http header.
  4. 中将此 JWT 作为承载发送
  5. 后端验证 JWT <==== 这就是我想知道如何在 Micronaut 中做到这一点。

问题

How do I load a “user” in a micronaut backend when JWT is provided?

我正在阅读这篇文章,因为您计划在您的数据库中加载某种 User 对象并在控制器中访问它。 如果是这种情况,您需要连接到创建身份验证实例的地方以读取令牌的“子”(用户名),然后从数据库加载它。

How to extend authentication attributes with more details ?

默认情况下,JWT 身份验证是使用 JwtAuthenticationFactory 创建的,更具体的默认实现是 DefaultJwtAuthenticationFactory。如果您计划加载更多声明,可以通过替换它并创建扩展的 JWTClaimsSet 或您自己的身份验证接口实现来完成。

How do I access jwt claims ?

您需要检查 SecurityService -> getAuthentication() ->getAttributes(),它 returns 代表序列化为映射的令牌的安全属性映射。

How to validate that the JWT is valid?

有一个基本的验证规则检查令牌是否过期和正确签名,所有其余的验证,特别是自定义声明和再次验证第三方来源必须自己完成。

如果你打算验证你的自定义声明,我已经在这个范围内开源了一个项目,请看一下。

https://github.com/traycho/micronaut-security-attributes

How to extend existing token with extra claims during its issuing ?

需要创建自己的声明生成器扩展 JWTClaimsSetGenerator

@Singleton
@Replaces(JWTClaimsSetGenerator)
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)

        // You your custom claims here
        builder.claim('email', userDetails.getAttributes().get("email"));

    }
}

我找到了解决办法。 UserDetails.attributes 被序列化到 JWT 中。它们可以很容易地在我的 CustomAuthenticationProviderclass:

中设置
@Singleton
@Slf4j
public class CustomAuthenticationProvider implements AuthenticationProvider {


    @Override
    public Publisher<AuthenticationResponse> authenticate(
        @Nullable HttpRequest<?> httpRequest, 
        AuthenticationRequest<?, ?> authenticationRequest) 
    {
        // ... autenticate the request here ...
        // eg. via BasicAuth or Oauth 2.0 OneTimeToken
        // then if valid:

        return Flowable.create(emitter -> {
            UserDetails userDetails = new UserDetails("sherlock", Collections.emptyList(), "sherlock@micronaut.example");

            // These attributes will be serialized as custom claims in the JWT
            Map attrs = CollectionUtils.mapOf("email", email, "teamId", teamId)
            userDetails.setAttributes(attrs);

            emitter.onNext(userDetails);
            emitter.onComplete();
        }, BackpressureStrategy.ERROR);
    }
}

在后端验证 JWT 时还有一些陷阱

Micronaut 中的 JWT 必须包含“sub”声明。 JWT 规范不需要这个,但 Micronaut 需要。 “sub”声明的值将成为创建的 UserDetails 对象的用户名。

如果你想在后端验证 JWT 时将附加属性加载到这些 UserDetails 中,那么你可以通过实现一个 TokenValidator 来实现。但是(另一个陷阱)然后你必须将它的 ORDER 设置为大于 micronaut 的 JwtTokenValidator 的值。您的订单必须 > 0 否则您的 TokenValidator 根本不会被调用.

How do I access jwt claims ?

如果您想从其余处理程序访问它们,只需在处理方法中添加 io.micronaut.security.authentication.Authentication 作为附加参数。例子

@Get("/{fooId}")
@Secured(SecurityRule.IS_AUTHENTICATED)
public HttpResponse<Foo> getFoo(long fooId, Authentication authentication) {
    ...
}