我有两个微服务,一个配置为OAuth2服务器-A,另一个配置为OAuth2客户端-B。我想在这两个微服务之间共享我的自定义用户。当用户通过AI进行身份验证时,创建UserDetails的自定义实现,我想保护B中的某些资源。因此,我配置了与A相同的资源服务器。我希望可以在以下两者之间共享UserDetails的自定义实现A和B使用主体。我能够从A中的主体获取自定义用户,但在B中,主体仅由String(username)表示。如何使资源服务器返回UserDetails的自定义实现,而不仅仅是用户名?
服务器配置:
@SpringBootApplication
@EnableResourceServer
@EnableAuthorizationServer
@EnableWebSecurity
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
UserDetailsService的实现,该实现返回我的实现UserDetails的CustomUser(为简单起见,只是一个虚拟用户)
@Service
@Primary
public class UserDetailsServiceImpl implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
GrantedAuthority authority = new Authority("USER");
return new CustomUser(5L, "username", "{noop}password", Arrays.asList(authority));
}
}
OAuth2服务器的配置:
@Configuration
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager)
.tokenStore(tokenStore());
}
@Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("user")
.secret("{noop}password")
.authorizedGrantTypes("password", "refresh_token")
.scopes("webapp");
}
}
WebSecurityConfigurerAdapter:
@Configuration
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
}
通过剩余的端点(仅返回主体),这是主体“应该”可被其他服务访问的方式,在这里服务A中包含CustomUser的实例:
@RestController
@RequestMapping("/user")
public class UserRestController {
@GetMapping("/auth")
public Principal getPrincipal(Principal principal) {
return principal;
}
}
Application.properties-来自A的终结点的URL
server.port=8081
security.oauth2.resource.user-info-uri=http://localhost:8080/user/auth
B的首发
@SpringBootApplication
@EnableResourceServer
@EnableWebSecurity
@EnableOAuth2Client
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
最后是我用来测试主体是字符串(用户名)还是CustomUser的rest控制器。不幸的是,主体始终只包含用户名和具有自定义用户值的字段映射。
@RestController
@RequestMapping("/client")
public class ClientRestController {
@GetMapping("/print")
public void printId(Principal principal) {
System.out.println(principal);
}
}
您能帮我解决吗?如何通过我的CustomUser传递Principal?
感谢帮助:)
答案 0 :(得分:0)
好吧,返回Principal对象不是一个好主意(很可能它将是其实现类UsernamePasswordAuthenticationToken
)。如果只希望端点共享自定义用户详细信息,那么最好的方法是创建一个仅包含您要公开的信息的数据传输对象。
建议的获取主体(提出请求的经过身份验证的用户)的方法是来自安全上下文。有关更多信息,请访问here。