RESPApi项目的设置是:
在项目中我们有很多客户端,因此SQL查询在"... and clientId = ?"
子句中几乎总是有where
。
我们将clientId
与SecurityContext
一起存储在其他用户详细信息中(我们扩展了Spring User
类)。
问题是:如何获取User
中的@Repository
对象?
我们可以想到的可能解决方案:
SecurityContextHolder.getContext().getAuthentication()
将结果转换为我们的自定义UserDetails实现并使用它。
缺点:我觉得有更好的解决方案。
@AuthenticationPrincipal
带注释的参数添加到控制器,然后将参数传递给服务层,然后传递到存储库层。 缺点:仅通过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,但我觉得必须有更好的方法。
任何想法如何解决这个问题?
答案 0 :(得分:1)
如果您正在使用Spring Data
(或有时间切换到使用它),则可以使用SecurityEvaluationContextExtension
并直接在查询中使用principal
:
https://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() {
.....
}