使用自定义 UserDetailsService 时 JWT 中不存在 OAuth2 GrantedAuthorities
OAuth2 GrantedAuthorities not present in JWT when using custom UserDetailsService
使用新的 spring-authorization-server 0.2.3 并遵循 https://github.com/spring-projects/spring-authorization-server/tree/main/samples 作为参考,我能够在使用 [=13] 时成功设置授权服务器、资源服务器和客户端=]如下
@EnableWebSecurity
public class DefaultSecurityConfig {
@Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
return http
.authorizeRequests(authorizeRequests ->
authorizeRequests.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults())
.build();
}
@Bean
UserDetailsService users() {
User.UserBuilder users = User.withDefaultPasswordEncoder();
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(users.username("user1").password("password").roles("USER").build());
manager.createUser(users.username("admin").password("password").roles("USER", "ADMIN").authorities("r1","r2","r3").build());
return manager;
}
}
这很有效,在客户端中,我可以看到权限 Granted Authorities=["r1","r2","r3"]
存在。
现在,当我尝试实现自己的 UserDetailsService
从 Mongo 数据库检索用户时,我不再看到传递给客户端的 GrantedAuthorities,而只看到 Granted Authorities=[ROLE_USER, SCOPE_openid]
这就是我现在在 DefaultSecurityConfig 中的内容
@EnableWebSecurity
public class DefaultSecurityConfig {
@Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
return http
.authorizeRequests(authorizeRequests ->
authorizeRequests.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults())
.build();
}
@Autowired
private MongoTemplate mongoTemplate;
@Bean
UserDetailsService users() {
return new CustomUserDetailsService(mongoTemplate);
}
}
我的 CustomUserDetailsService
如下所示:
public class CustomUserDetailsService implements UserDetailsService {
private final MongoTemplate mongoTemplate;
public CustomUserDetailsService(MongoTemplate mongoTemplate) {
this.mongoTemplate = mongoTemplate;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Criteria criteria = Criteria.where("email").is(username);
CustomUser user = mongoTemplate.findOne(new Query(criteria), CustomUser.class, "vOAuthUser");
if (user != null) {
log.info("Found user {}", user.email());
List<GrantedAuthority> authorities = getUserAuthority(user.groups());
return buildUserForAuthentication(user, authorities);
} else {
throw new UsernameNotFoundException("username not found");
}
}
private UserDetails buildUserForAuthentication(CustomUser user, List<GrantedAuthority> authorities) {
return new org.springframework.security.core.userdetails.User(user.email(), user.password(), authorities);
}
private List<GrantedAuthority> getUserAuthority(Set<String> groups) {
List<GrantedAuthority> authorities = new ArrayList<>();
groups.forEach(s -> {
Criteria criteria = Criteria.where("name").is(s);
CustomRole role = mongoTemplate.findOne(new Query(criteria), CustomRole.class, "vRole");
if (role != null) {
authorities.addAll(role.grantedAuthorities());
}
});
return authorities;
}
}
Any help is greatly appreciated.
您是否在安全配置中定义了 OAuth2 Token Customizer bean?如果需要,您可以在那里添加 Granted Authorities,如以下代码所示:
@Bean
@SuppressWarnings("unused")
OAuth2TokenCustomizer<JwtEncodingContext> jwtCustomizer() {
return context -> {
JoseHeader.Builder headers = context.getHeaders();
JwtClaimsSet.Builder claims = context.getClaims();
Authentication principal = context.getPrincipal();
Set<String> authorities = principal.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.toSet());
claims.claim("authorities", authorities);
};
}
使用新的 spring-authorization-server 0.2.3 并遵循 https://github.com/spring-projects/spring-authorization-server/tree/main/samples 作为参考,我能够在使用 [=13] 时成功设置授权服务器、资源服务器和客户端=]如下
@EnableWebSecurity
public class DefaultSecurityConfig {
@Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
return http
.authorizeRequests(authorizeRequests ->
authorizeRequests.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults())
.build();
}
@Bean
UserDetailsService users() {
User.UserBuilder users = User.withDefaultPasswordEncoder();
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(users.username("user1").password("password").roles("USER").build());
manager.createUser(users.username("admin").password("password").roles("USER", "ADMIN").authorities("r1","r2","r3").build());
return manager;
}
}
这很有效,在客户端中,我可以看到权限 Granted Authorities=["r1","r2","r3"]
存在。
现在,当我尝试实现自己的 UserDetailsService
从 Mongo 数据库检索用户时,我不再看到传递给客户端的 GrantedAuthorities,而只看到 Granted Authorities=[ROLE_USER, SCOPE_openid]
这就是我现在在 DefaultSecurityConfig 中的内容
@EnableWebSecurity
public class DefaultSecurityConfig {
@Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
return http
.authorizeRequests(authorizeRequests ->
authorizeRequests.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults())
.build();
}
@Autowired
private MongoTemplate mongoTemplate;
@Bean
UserDetailsService users() {
return new CustomUserDetailsService(mongoTemplate);
}
}
我的 CustomUserDetailsService
如下所示:
public class CustomUserDetailsService implements UserDetailsService {
private final MongoTemplate mongoTemplate;
public CustomUserDetailsService(MongoTemplate mongoTemplate) {
this.mongoTemplate = mongoTemplate;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Criteria criteria = Criteria.where("email").is(username);
CustomUser user = mongoTemplate.findOne(new Query(criteria), CustomUser.class, "vOAuthUser");
if (user != null) {
log.info("Found user {}", user.email());
List<GrantedAuthority> authorities = getUserAuthority(user.groups());
return buildUserForAuthentication(user, authorities);
} else {
throw new UsernameNotFoundException("username not found");
}
}
private UserDetails buildUserForAuthentication(CustomUser user, List<GrantedAuthority> authorities) {
return new org.springframework.security.core.userdetails.User(user.email(), user.password(), authorities);
}
private List<GrantedAuthority> getUserAuthority(Set<String> groups) {
List<GrantedAuthority> authorities = new ArrayList<>();
groups.forEach(s -> {
Criteria criteria = Criteria.where("name").is(s);
CustomRole role = mongoTemplate.findOne(new Query(criteria), CustomRole.class, "vRole");
if (role != null) {
authorities.addAll(role.grantedAuthorities());
}
});
return authorities;
}
}
Any help is greatly appreciated.
您是否在安全配置中定义了 OAuth2 Token Customizer bean?如果需要,您可以在那里添加 Granted Authorities,如以下代码所示:
@Bean
@SuppressWarnings("unused")
OAuth2TokenCustomizer<JwtEncodingContext> jwtCustomizer() {
return context -> {
JoseHeader.Builder headers = context.getHeaders();
JwtClaimsSet.Builder claims = context.getClaims();
Authentication principal = context.getPrincipal();
Set<String> authorities = principal.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.toSet());
claims.claim("authorities", authorities);
};
}