我有一个用@PreAuthorize保护的方法
@PreAuthorize("hasRole('ROLE_ADMIN') and (#action.userId != principal.id)")
public void execute(EditAction action)
现在我需要从后台任务调用此方法。如果我只是运行这段代码 - 我发现一个异常:
AuthenticationCredentialsNotFoundException:在 SecurityContext 中找不到 Authentication 对象
似乎,我需要将所需的身份验证设置为安全上下文。我可以:
- 为后台任务编写一些自定义身份验证令牌。
- 将 UsernamePasswordAuthenticationToken 与假用户一起使用。
- 不要在后台任务中使用安全方法。
- 还有其他建议吗?
正确的方法是什么?
手动解决方法是一个选项:
(1)如果这是一项独立的工作,
在调用安全方法之前,创建一个身份验证对象并将其设置为安全上下文。在安全方法执行完毕后,从安全上下文中删除身份验证对象。
public final class AuthenticationUtil {
//Ensures that this class cannot be instantiated
private AuthenticationUtil() {
}
public static void clearAuthentication() {
SecurityContextHolder.getContext().setAuthentication(null);
}
public static void configureAuthentication(String role) {
Collection<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList(role);
Authentication authentication = new UsernamePasswordAuthenticationToken(
"user",
role,
authorities
);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
所以它看起来像
AuthenticationUtil.configureAuthentication(role);
// Call to the secured method
AuthenticationUtil.clearAuthentication();
(2)对于Web应用,我们不能将认证对象设为null,不要调用
AuthenticationUtil.configureAuthentication(role);
// call to the secured method
您可以在当前线程和会话中自行注册身份验证令牌(如果在 Web 应用程序中使用):
SecurityContextHolder.getContext().setAuthentication(token);
session.put(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext());
只要添加适当的角色,就可以为此使用标准的 UsernamePasswordAuthenticationToken。