Spring REST Api - 访问存储库

时间:2017-07-24 11:28:44

标签: java spring spring-mvc spring-security spring-security-oauth2

RESPApi项目的设置是:

  • SpringBoot
  • Spring的OAuth2

在项目中我们有很多客户端,因此SQL查询在"... and clientId = ?"子句中几乎总是有where

我们将clientIdSecurityContext一起存储在其他用户详细信息中(我们扩展了Spring User类)。

问题是:如何获取User中的@Repository对象?

我们可以想到的可能解决方案:

  1. 在每个存储库实现中添加
  2. SecurityContextHolder.getContext().getAuthentication()

    将结果转换为我们的自定义UserDetails实现并使用它。

    缺点:我觉得有更好的解决方案。

    1. @AuthenticationPrincipal带注释的参数添加到控制器,然后将参数传递给服务层,然后传递到存储库层。
    2. 缺点:仅通过2层传递参数以获得clientId似乎并不合理。

      我在@Autowired课程中考虑了MyUser user参数@Repository。第一个尝试是创建@Configuration带注释的类,其中将有一个方法

          @Bean
      public MyUser getUser() {
          SecurityContext context = SecurityContextHolder.getContext();
          if (context != null) {
              Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
              if (authentication != null) {
                  return (MyUser) authentication.getPrincipal();
              }
          }
          return null;
      }
      

      但bean是null,我不能使用它。

      目前我们已经找到解决方案nr 1,但我觉得必须有更好的方法。

      任何想法如何解决这个问题?

2 个答案:

答案 0 :(得分:1)

如果您正在使用Spring Data(或有时间切换到使用它),则可以使用SecurityEvaluationContextExtension并直接在查询中使用principalhttps://stackoverflow.com/a/29692158/1777072

如果没有,您可以隐藏静态访问(如果它冒犯了(或者如果您希望将来更多地控制它):

@Component
public class AuthenticationHelper {
    public Authentication getAuthentication() {
        return SecurityContextHolder.getContext().getAuthentication();
    }
}

然后将该类注入您的存储库。

或您的服务。这可能比存储库更合适。

我喜欢让Repositories变得愚蠢(最终使用Spring Data来避免完全编写它们)。

我喜欢将服务视为从Web层分离出来,在不同的盒子上运行(即使它们不是)。在这种情况下,您永远不会通过HTTP将身份验证详细信息从Controller传递到服务。该服务将获取自身的身份验证详细信息,而不仅仅是信任Web层发送的内容。

所以我认为服务应该自己获取细节,而不是控制器传递它们。

答案 1 :(得分:0)

你的bean是null,因为默认的bean是单例,它们是在应用程序启动时创建的,你可以想象,那时你不会有SecurityContext

尝试以这种方式声明具有请求范围的bean:

@Bean
@Scope(value=WebApplicationContext.SCOPE_REQUEST, proxyMode=ScopedProxyMode.TARGET_CLASS)
public MyUser getUser() {
   .....
}