Dan*_*Dan 3 jwt spring-security-oauth2
我们有一个使用 JWT 在服务之间进行身份验证的微服务架构。我希望轻松地从 JWT 中获取更多字段。目前,Spring Security 直接暴露了权限。
我们的边缘服务/API 网关创建以传递给下游服务的示例 JWT(某些字段是为我们的应用程序自定义的):
{
"projectId": "project1",
"group": "client",
"iss": "login.company.com",
"aud": "company.com",
"sub": "testguy",
"exp": 1461074284992,
"projectRoleId": "ADMINPAG",
"contentAccessGroupId": "CAG1",
"authorities": [
"client",
"PROJECT_ADD_USER",
"PROJECT_ADD_CAG",
"PROJECT_DOCUMENT_VIEW",
"PROJECT_EDIT_CAG",
"PROJECT_LIST_USERS",
"PROJECT_SEARCH"
],
"user_name": "test@company.com"
}
Run Code Online (Sandbox Code Playgroud)
在 Spring Boot 中使用它非常容易:
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')
Run Code Online (Sandbox Code Playgroud)
1)注解应用类
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MyApp {
Run Code Online (Sandbox Code Playgroud)
2) 将属性添加到 application.yml 以配置忽略的路径和 JWT 密钥:
security:
basic:
enabled: false
oauth2:
resource.jwt.keyValue: itsasecret
ignored:
- /
- /swagger-ui.html
- /webjars/**
- /swagger-resources
- /swagger/**
Run Code Online (Sandbox Code Playgroud)
这会导致用户在检测到 JWT 时自动登录。我可以@PreAuthorize("hasAuthority('PROJECT_SEARCH')")很好地断言他们的权限。
唯一剩下的就是我希望能够从 JWT 中获取其他字段(例如“子”-用户 ID)。此信息似乎存储在 OAuth2AccessToken#getAdditionalInformation() 字段中。自定义 UserDetails 实现在这里可以正常工作,但我希望能够直接从 JWT 创建 UserDetails,而不是通过 UserDetailsService (它根据用户名创建一个)。
例如,我的主要目标是能够从 PreAuthorize 注释中引用其中一些 JWT 字段,以断言当前用户的 ID 与“userId”参数中传递的 ID 相同。如果可能的话,如果为此所需的配置更改可以隔离到共享模块中的 AutoConfiguration 类,我会很高兴,这样我们就不必接触我们所有的服务。JWT 本身的结构是 100% 灵活的。
在 Spring Cloud Docs 上找到了解决方案。
我在这里想要的是 JwtAccessTokenConverterConfigurer。
下面的类是自动检测到的,一旦 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;
}
}
Run Code Online (Sandbox Code Playgroud)
这里唯一需要注意的是,我的自定义用户详细信息对象需要额外的跳转才能到达。它实际上是作为默认用户详细信息对象上的一个字段创建的,称为 decodedDetails。我刚刚制作了一个自定义方法参数解析器来帮助检索:
@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();
}
};
}
}
Run Code Online (Sandbox Code Playgroud)
这只是允许您将自定义用户详细信息作为参数传递给控制器,并从 JWT 自动填充它:
@RequestMapping("/currentUser")
public UserInfoResponse getCurrentUser(MyAppCustomUserDetails user){
//do stuff
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3256 次 |
| 最近记录: |