我认为this answer 可以帮助您解决问题,即使您不使用 Spring Data MongoDB。
基本上,您需要实现UserDetailsService 接口并将其注释为@Component 或@Service bean。
那你需要自己实现一个UserDetails POJO(例子很多)。
最后,您需要使用自定义的 UserService 配置 Spring Security,这对于 Spring Boot 来说非常简单。
因此,如果您还没有使用Spring Boot,我强烈建议您这样做。它使 Spring 开发人员的生活变得如此轻松。
为了保护您的 REST 端点,您可以创建某种 PermissionService(常规 Spring @Service bean)来检查当前用户是否被允许访问/编辑资源。
例子:
@Slf4j
@Service
public class PermissionService {
public boolean hasPermission(String userId, String resourceId) {
log.debug("Checking permission for [{}] on resource [{}]", userId, resourceId);
hasText(userId);
hasText(resourceId);
return resourceId == 1;
}
}
在任何 @RestController 中,您现在可以添加 Spring Security 注释并使用 SPEL(Spring 表达式语言)来评估条件:
@RestController
@RequestMapping("/api/resource")
public class ResourceController {
@GetMapping("/{id}")
@PreAuthorize("@permissionService.hasPermission(userDetails.userId, resourceId)")
public ResponseEntity findResource(@PathVariable("id") String resourceId, @MyUser SecUserDetails userDetails) {
return ResponseEntity.ok(resourceRepository.findById(resourceId));
}
}
现在,你一定在想:这个奇怪的@MyUser 注释是什么?嗯,它是一个自定义注解,可以将当前 Spring Security UserDetails 实例注入到控制器方法中。
你可以这样定义:
@Slf4j
@Component
public class MyUserMethodArgumentResolver implements HandlerMethodArgumentResolver {
private final UserService userService;
@Autowired
public MyUserMethodArgumentResolver(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
return methodParameter.getParameterAnnotation(MyUser.class) != null
&& methodParameter.getParameterType().equals(SecUserDetails.class);
}
@Override
public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
if (this.supportsParameter(methodParameter)) {
return this.userService.getCurrentUser();
} else {
return WebArgumentResolver.UNRESOLVED;
}
}
}
因此,每当控制器找到此 @MyUser 注释时,它都会调用此 WebArgumentResolver 来检索当前用户详细信息(SecUserDetails 实例)并将其注入控制器方法中。
然后可以在PermissionService中使用它来检查访问权限。