Spring Security无状态JWT身份验证-如何获取其他JWT字段?
我们有一个微服务体系结构,使用JWT在服务之间进行身份验证。我希望能够轻松地从JWT中获取更多字段。目前真的只是当局被Spring Security直接曝光 我们的边缘服务/API网关创建的传递给下游服务的示例JWT(一些字段是我们的应用程序自定义的): 使用Spring Boot很容易做到这一点:Spring Security无状态JWT身份验证-如何获取其他JWT字段?,jwt,spring-security-oauth2,Jwt,Spring Security Oauth2,我们有一个微服务体系结构,使用JWT在服务之间进行身份验证。我希望能够轻松地从JWT中获取更多字段。目前真的只是当局被Spring Security直接曝光 我们的边缘服务/API网关创建的传递给下游服务的示例JWT(一些字段是我们的应用程序自定义的): 使用Spring Boot很容易做到这一点: compile("org.springframework.boot:spring-boot-starter-security:1.3.1") compile('org.springframework
compile("org.springframework.boot:spring-boot-starter-security:1.3.1")
compile('org.springframework.security.oauth:spring-security-oauth2:2.0.8.RELEASE')
compile('org.springframework.security:spring-security-jwt:1.0.3.RELEASE')
1) 注释应用程序类
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MyApp {
2) 将属性添加到application.yml以配置忽略的路径和JWT键:
security:
basic:
enabled: false
oauth2:
resource.jwt.keyValue: itsasecret
ignored:
- /
- /swagger-ui.html
- /webjars/**
- /swagger-resources
- /swagger/**
这会导致用户在检测到JWT时自动登录。我可以通过@PreAuthorize(“hasAuthority('PROJECT_SEARCH')”)
对他们的权限进行断言
剩下的唯一一件事是我希望能够从JWT中获取其他字段(例如“sub”-用户id)。此信息似乎存储在OAuth2AccessToken#getAdditionalInformation()字段中。自定义UserDetails实现在这里可以正常工作,但我希望能够直接从JWT创建UserDetails,而不是通过UserDetailsService(它基于用户名创建一个)
我的主要目标是能够引用预授权注释中的一些JWT字段,以断言当前用户的ID与在“userId”参数中传递的ID相同。如果可能的话,我希望能够将为此所需的配置更改隔离到共享模块中的自动配置类中,这样我们就不必接触所有的服务。JWT本身的结构是100%灵活的。在Spring Cloud文档中找到了解决方案 我想要的是一个JWTAccessTokenConverterConfiguration 下面的类是自动检测的,一旦读取JWT,它将为您创建一个自定义OAuth2Authentication对象:
@Component
public class JwtConverter extends DefaultAccessTokenConverter implements
JwtAccessTokenConverterConfigurer {
@Override
public void configure(JwtAccessTokenConverter converter) {
converter.setAccessTokenConverter(this);
}
@Override
public OAuth2Authentication extractAuthentication(Map<String, ?> map) {
OAuth2Authentication auth = super.extractAuthentication(map);
MyAppCustomUserDetails details = new MyAppCustomUserDetails();
//populate details from the provided map, which contains the whole JWT.
auth.setDetails(details);
return auth;
}
}
@Component
public class JwtConverter extends DefaultAccessTokenConverter implements
JwtAccessTokenConverterConfigurer {
@Override
public void configure(JwtAccessTokenConverter converter) {
converter.setAccessTokenConverter(this);
}
@Override
public OAuth2Authentication extractAuthentication(Map<String, ?> map) {
OAuth2Authentication auth = super.extractAuthentication(map);
MyAppCustomUserDetails details = new MyAppCustomUserDetails();
//populate details from the provided map, which contains the whole JWT.
auth.setDetails(details);
return auth;
}
}
@Configuration
@ConditionalOnBean(JwtConverter.class)
public class WebConfigurer extends WebMvcConfigurerAdapter {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(currentUserHandlerMethodArgumentResolver());
super.addArgumentResolvers(argumentResolvers);
}
@Bean
public HandlerMethodArgumentResolver currentUserHandlerMethodArgumentResolver() {
return new HandlerMethodArgumentResolver() {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType().equals(MyAppCustomUserDetails.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
return ((OAuth2AuthenticationDetails) SecurityContextHolder.getContext().getAuthentication().getDetails()).getDecodedDetails();
}
};
}
}
@RequestMapping("/currentUser")
public UserInfoResponse getCurrentUser(MyAppCustomUserDetails user){
//do stuff
}