提供 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“声明”吗?
- 是否需要从我的数据库中通过用户名加载相应的用户table?
- 如何验证发送的用户名是否有效?
编辑 更详细地描述我的用例:
我的用例的安全要求
- 不向客户端暴露有效信息
- 验证客户端(移动应用程序)通过 REST 发送的所有内容
身份验证流程
带有 JWT 的默认 oauth2 流程:
前提条件:用户已经注册。后端已知用户名、哈希(密码)和其他属性(电子邮件、地址、teamId 等)。
- 客户端将用户名和密码发送到 /login 端点
- 客户端在 return 中接收 JWT,使用服务器密钥签名
- 在以后的每个请求中,客户端都会在 Http header.
中将此 JWT 作为承载发送
- 后端验证 JWT <==== 这就是我想知道如何在 Micronaut 中做到这一点。
问题
- 如何验证 JWT 是否有效?
- 我应该Java class 如何以及在何处获取该用户的附加信息(附加属性)。我应该使用什么 ID 来获取此信息。来自解码的 JWT 的“sub”或“name”?
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 中。它们可以很容易地在我的 CustomAuthenticationProvider
class:
中设置
@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) {
...
}
我有一个通过 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“声明”吗?
- 是否需要从我的数据库中通过用户名加载相应的用户table?
- 如何验证发送的用户名是否有效?
编辑 更详细地描述我的用例:
我的用例的安全要求
- 不向客户端暴露有效信息
- 验证客户端(移动应用程序)通过 REST 发送的所有内容
身份验证流程
带有 JWT 的默认 oauth2 流程:
前提条件:用户已经注册。后端已知用户名、哈希(密码)和其他属性(电子邮件、地址、teamId 等)。
- 客户端将用户名和密码发送到 /login 端点
- 客户端在 return 中接收 JWT,使用服务器密钥签名
- 在以后的每个请求中,客户端都会在 Http header. 中将此 JWT 作为承载发送
- 后端验证 JWT <==== 这就是我想知道如何在 Micronaut 中做到这一点。
问题
- 如何验证 JWT 是否有效?
- 我应该Java class 如何以及在何处获取该用户的附加信息(附加属性)。我应该使用什么 ID 来获取此信息。来自解码的 JWT 的“sub”或“name”?
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 中。它们可以很容易地在我的 CustomAuthenticationProvider
class:
@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) {
...
}