我正在构建一个Spring Boot应用程序以提供无状态REST API。为了安全起见,我们使用的是OAuth2。我的应用程序收到仅承载令牌。
用户信息存储在我们的数据库中。我可以使用控制器中注入的Principal进行查找:
@RequestMapping(...)
public void endpoint(Principal p) {
MyUser user = this.myUserRepository.findById(p.getName());
...
}
为了避免多余的内容,我希望能够将MyUser对象直接注入到我的控制器方法中。我该如何实现? (到目前为止,我想出的最好的办法是创建一个懒惰的,请求范围的@Bean ...但是我无法使其正常工作...)
答案 0 :(得分:0)
Spring Security的惯用方式是use a UserDetailsService
或implement your own:
public class MyUserDetailsService implements UserDetailsService {
@Autowired
MyUserRepository myUserRepository;
public UserDetails loadUserByUsername(String username) {
return this.myUserRepository.findById(username);
}
}
然后,根据您的需要,Spring Security DSL中会有几个可以存放的地方。
一旦与您使用的身份验证方法集成在一起(在本例中为OAuth 2.0),您就可以做到:
public void endpoint(@AuthenticationPrincipal MyUser myuser) {
}
通常最好在身份验证时(确定Principal时)执行此操作,而不是在方法解析时(使用参数解析器)执行此操作,因为这样可以在更多身份验证场景中使用它。
也就是说,您还可以将@AuthenticationPrincipal
参数解析器与已注册的任何bean一起使用,例如
public void endpoint(
@AuthenticationPrincipal(expression="@myBean.convert(#this)") MyUser user)
{
}
...
@Bean
public Converter<Principal, MyUser> myBean() {
return principal -> this.myUserRepository.findById(p.getName())
}
权衡是每次调用此方法时都将执行此转换。由于您的应用是无状态的,因此这可能不是问题(因为无论如何都需要对每个请求执行查找),但这意味着该控制器可能无法在其他应用配置文件中重复使用。
答案 1 :(得分:-1)
您可以通过实现HandlerMethodArgumentResolver来实现。 例如:
自定义注释:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface Version {
}
实施:
public class HeaderVersionArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
return methodParameter.getParameterAnnotation(Version.class) != null;
}
@Override
public Object resolveArgument(
MethodParameter methodParameter,
ModelAndViewContainer modelAndViewContainer,
NativeWebRequest nativeWebRequest,
WebDataBinderFactory webDataBinderFactory) throws Exception {
HttpServletRequest request
= (HttpServletRequest) nativeWebRequest.getNativeRequest();
return request.getHeader("Version");
}
}
实现此功能时,应将其添加为参数解析器:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addArgumentResolvers(
List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new HeaderVersionArgumentResolver());
}
}
现在我们可以将其用作参数
public ResponseEntity findByVersion(@PathVariable Long id, @Version String version)