为了账号安全,请及时绑定邮箱和手机立即绑定

Spring boot:将请求范围的、延迟初始化的自定义用户对象注入控制器

Spring boot:将请求范围的、延迟初始化的自定义用户对象注入控制器

梵蒂冈之花 2022-06-30 10:30:39
我正在构建一个 Spring Boot 应用程序来提供无状态的 REST API。为安全起见,我们使用 OAuth 2。我的应用程序接收到不记名令牌。用户的信息存储在我们的数据库中。我可以使用控制器中注入的 Principal 来查找它:@RequestMapping(...)public void endpoint(Principal p) {  MyUser user = this.myUserRepository.findById(p.getName());  ...}为了避免这种额外的样板代码行,我希望能够将 MyUser 对象直接注入到我的控制器方法中。我怎样才能做到这一点?(到目前为止,我想出的最好的方法是创建一个惰性的、请求范围的 @Bean ......但我无法让它工作......)
查看完整描述

2 回答

?
aluckdog

TA贡献1847条经验 获得超7个赞

惯用的方式

Spring Security 的惯用方式是使用UserDetailsService或实现您自己的:


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())

}

权衡是每次调用此方法时都将执行此转换。由于您的应用程序是无状态的,这可能不是问题(因为无论如何都需要对每个请求执行查找),但这意味着该控制器可能无法在其他应用程序配置文件中重用。


查看完整回答
反对 回复 2022-06-30
?
GCT1015

TA贡献1827条经验 获得超4个赞

您可以通过实现 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) 



查看完整回答
反对 回复 2022-06-30
  • 2 回答
  • 0 关注
  • 294 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信