1

我有一个 Micronaut 微服务,它通过本指南中的JsonWebTokens (JWT) 处理身份验证。

现在我想扩展这段代码。我的应用程序中的用户有一些额外的属性,例如电子邮件、地址、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 的“声明”吗?
  • 我是否需要通过数据库表中的用户名加载相应的用户?
  • 如何验证发送的用户名是否确实有效?

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

我的用例的安全要求

  • 不要向客户公开有效信息
  • 验证客户端(移动应用程序)通过 REST 发送的所有内容

身份验证流程

带有 JWT 的默认 oauth2 流:

前提条件:用户已经注册。用户名、哈希(密码)和其他属性(电子邮件、地址、团队 ID、..)在后端是已知的。

  1. 客户端 POST 用户名和密码到 /login 端点
  2. 客户端收到 JWT 作为回报,使用服务器密码签名
  3. 在以后的每个请求中,客户端都会将此 JWT 作为 Http 标头中的承载发送。
  4. 后端验证 JWT <==== 这是我想知道如何在 Micronaut 中执行此操作的内容。

问题

  • 如何验证 JWT 是否有效?
  • 我应该如何以及在哪个 Java 类中获取该用户的附加信息(附加属性)。我应该使用什么 ID 来获取此信息。解码后的 JWT 中的“子”或“名称”?
4

3 回答 3

2

提供 JWT 时,如何在 micronaut 后端加载“用户”?

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

如何使用更多细节扩展身份验证属性?

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

如何访问 jwt 声明?

您需要检查SecurityService -> getAuthentication() ->getAttributes(),它会返回一个安全属性映射,这些属性表示您的令牌序列化为映射。

如何验证 JWT 是否有效?

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

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

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

如何在发行期间通过额外的声明来扩展现有的令牌?

需要创建自己的索赔生成器扩展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"));

    }
}
于 2020-08-18T19:18:04.280 回答
1

如何访问 jwt 声明?

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

@Get("/{fooId}")
@Secured(SecurityRule.IS_AUTHENTICATED)
public HttpResponse<Foo> getFoo(long fooId, Authentication authentication) {
    ...
}
于 2020-12-17T20:27:42.293 回答
-1

我找到了解决方案。被UserDetails.attributes序列化到 JWT 中。他们可以很容易地在我的CustomAuthenticationProvider课堂上设置:

@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 必须包含“子”声明。JWT 规范不需要这样做,但 Micronaut 需要。“sub”声明的值将成为创建UserDetails对象的用户名。

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

于 2020-08-19T10:10:52.480 回答