java - 在 Spring Boot 中从 jwt 获取附加属性
问题描述
我正在开发一个受 keycloak 保护的 Spring Boot 服务,它接受 jwt 不记名令牌进行身份验证。
我还配置了 swagger 并将其注册为公共客户端,因此当我从 swagger-ui 发出请求时,keycloak 会生成一个 JWT 令牌,然后在向 api 发出请求时将其用于身份验证。
我还为用户信息创建了 2 个额外的私有映射器。现在我想在我的 spring 控制器中获取这两个属性。
贝娄是我的示例代码。
我对 spring security 和各种做事方式(spring security / oauth2 / keycloak 等)感到有点迷茫,所以对解决方案的一些解释将不胜感激。
pom.xml
<!-- spring security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- spring security test -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<!-- KeyCloak -->
<!-- https://mvnrepository.com/artifact/org.keycloak/keycloak-spring-boot-2-starter -->
<!-- https://stackoverflow.com/questions/50243088/keycloak-4-0-0-beta-2-with-spring-boot-2 --> <!---->
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-2-starter</artifactId>
<version>4.0.0.Final</version>
</dependency>
春季安全配置
@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(
AuthenticationManagerBuilder auth) throws Exception {
KeycloakAuthenticationProvider keycloakAuthenticationProvider
= keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(
new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}
@Bean
public KeycloakSpringBootConfigResolver KeycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
@Bean
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(
new SessionRegistryImpl());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.authorizeRequests()
.antMatchers("/test*")
.hasRole("user")
.anyRequest()
.permitAll();
}
}
示例控制器
@RequestMapping(value = "HelloWorld1", method = RequestMethod.GET)
@ApiOperation(value = "HelloWorld1", produces = "application/json")
@ResponseBody
public String HelloWorld1(Principal principal) {
//I'd like something like this to work:
//String attr = principal.getAttribute("attribute1");
//
System.out.println(principal.getName());
RestTemplate restTemplate = new RestTemplate();
String text = restTemplate.getForObject(
"http://localhost:8080/test/test/HelloWorld", String.class);
return "Hello " + principal.getName() + " " + "it works! \n " + text;
}
解决方案
我不知道 Keycloak Spring 适配器,但您可以使用 Spring Security OAuth2 的 Spring Boot 模块执行此操作。Spring I/O 2019 实验室之一提供了一个很好的教程,显示 1)如何根据 Spring Security DSL 中的一些 JWT 声明(或从 UserInfo 端点检索到的声明)进行授权;2) 如何提取属性以在 Web 控制器、网页等中使用它们。请参阅那里的“实现客户端”部分。
基本上,你需要在你的项目中添加这个依赖(Gradle语法,请适应Maven):
implementation('org.springframework.boot:spring-boot-starter-oauth2-client')
然后:
基于 OIDC 属性/声明的 Spring Security DSL (HTTP Security) 中的授权
@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.fullyAuthenticated()
.and()
.oauth2Client()
.and()
.oauth2Login()
.userInfoEndpoint()
.userAuthoritiesMapper(userAuthoritiesMapper());
}
private GrantedAuthoritiesMapper userAuthoritiesMapper() {
return (authorities) -> {
Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
authorities.forEach(
authority -> {
if (authority instanceof OidcUserAuthority) {
OidcUserAuthority oidcUserAuthority = (OidcUserAuthority) authority;
OidcIdToken idToken = oidcUserAuthority.getIdToken();
OidcUserInfo userInfo = oidcUserAuthority.getUserInfo();
List<SimpleGrantedAuthority> groupAuthorities =
userInfo.getClaimAsStringList("groups").stream()
.map(g -> new SimpleGrantedAuthority("ROLE_" + g.toUpperCase()))
.collect(Collectors.toList());
mappedAuthorities.addAll(groupAuthorities);
}
});
return mappedAuthorities;
};
}
}
在 Web 控制器中使用 OIDC 声明/属性
@GetMapping("/")
Mono<String> index(@AuthenticationPrincipal OAuth2User oauth2User, Model model) {
model.addAttribute("fullname", oauth2User.getName());
model.addAttribute(
"isCurator",
((JSONArray) oauth2User.getAttributes().get("groups")).get(0).equals("library_curator"));
...
}
来源:https ://github.com/andifalk/oidc-workshop-spring-io-2019/tree/master/lab2#implement-the-client
推荐阅读
- php - Laravel 文档多次上传未保存到数据库
- xcode - 文件选择上的 iCloud Drive 不起作用
- java-11 - Java11 中 AuthCacheValue 和 AuthCacheImpl 的替代方案是什么
- flutter - 如何在flutter中实现搜索listview
- javascript - 在 TypeScript 映射中使用默认参数理解 HOF
- javascript - React 渲染元素无效,而导入和导出似乎没问题
- kubernetes - Spring 批处理工作程序 pod 仅安排 2 个工作程序节点
- postgresql - Docker 撰写将 ECONNREFUSED 127.0.0.1:3333 与 AdonisJS、Postgres 连接
- bash - Bash:使用 printf 在动态终端宽度的任一侧填充中心和彩色文本
- javascript - 从不同的父级中删除类