Cem*_*emo 5 spring spring-security
servletApi()对Spring Security的支持很棒.
我想注入自定义Principal:
public interface UserPrincipal extends Principal {
public Integer getId();
}
@RequestMapping(value = "/")
public ResponseEntity<List<Conversation>> listAfter(UserPrincipal user){
// implementation
}
or
@RequestMapping(value = "/")
public ResponseEntity<List<Conversation>> listAfter(UserPrincipalImpl user){
// implementation
}
Run Code Online (Sandbox Code Playgroud)
Spring支持在Principal实例的帮助下注入实例ServletRequestMethodArgumentResolver.
这是注射校长:
else if (Principal.class.isAssignableFrom(paramType)) {
return request.getUserPrincipal();
}
Run Code Online (Sandbox Code Playgroud)
这是问题开始的地方.request在这里是一个例子SecurityContextHolderAwareRequestWrapper.它有一个实现:
@Override
public Principal getUserPrincipal() {
Authentication auth = getAuthentication();
if ((auth == null) || (auth.getPrincipal() == null)) {
return null;
}
return auth;
}
Run Code Online (Sandbox Code Playgroud)
因为一个Authentication也是一个Principal.(到目前为止我不喜欢弹簧安全的唯一部分.我也会问这个问题.)
这导致了一个问题.因为Authentication是Principal不是UserPrincipal.
我该如何解决这个问题?我是否还需要实现UserPrincipal的身份验证?或者我应该更改HandlerMethodArgumentResolver命令创建一个自定义解析器?(这对于Spring MVC来说并不容易,因为内部处理程序具有更高的优先级.)
作为额外信息:
我正在使用Spring Security M2,我的配置AuthenticationManagerBuilder很简单:
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(detailsService);
}
Run Code Online (Sandbox Code Playgroud)
有帮助吗?
Rob*_*nch 14
从根本上说,这似乎是与Spring MVC集成的问题,而不是Spring Security问题.由于API返回一个Object,Spring Security无法知道Authentication @ getPrinicpal()实现了Principal.
我为你看了几个选项.每个都有一些优点和缺点,但我认为最好的是使用@ModelAttribute和@ControllerAdvice
@ModelAttribute 和 @ControllerAdvice最简单的选项是使用@ModelAttributeon custom 注释方法@ControllerAdvice.您可以在Spring Reference中找到详细信息.
@ControllerAdvice
public class SecurityControllerAdvice {
@ModelAttribute
public UserPrincipal customPrincipal(Authentication a) {
return (UserPrincipal) a == null ? null : a.getPrincipal();
}
}
Run Code Online (Sandbox Code Playgroud)
现在在您的控制器中,您可以执行以下操作:
@RequestMapping(value = "/")
public ResponseEntity<List<Conversation>> listAfter(@ModelAttribute UserPrincipal user){
// implementation
}
Run Code Online (Sandbox Code Playgroud)
请注意,@ModelAttribute只有确保@ModelAttribute在HttpServletRequest#getPrincipal()上使用它才是必需的.如果它没有实现Principal,@ModelAttribute则不是必需的.
@Value 和ExpressionValueMethodArgumentResolver你也可以这样做:
@RequestMapping(value = "/")
public ResponseEntity<List<Conversation>> listAfter(
@Value("#{request.userPrincipal.principal}") UserPrincipal user){
// implementation
}
Run Code Online (Sandbox Code Playgroud)
这是因为HttpServletRequest可用作ExpressionValueMethodArgumentResolver的属性(由Spring MVC默认添加),允许通过SpEL访问内容.我发现这不如注释@ModelAttribute中必须存在的常量那么吸引人@Value.SPR-10760解析后会更好,这样可以使用自己的自定义注释,如:
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Value("#{request.userPrincipal.principal}")
public @interface CurrentUser { }
Run Code Online (Sandbox Code Playgroud)
这有点草率,因为RequestMappingHandlerAdapter已经初始化,但您可以更改HandlerMethodArgumentResolvers的顺序,如下所示:
@EnableWebMvc
@Configuration
public class WebMvcConfiguration
extends WebMvcConfigurerAdapter {
...
@Autowired
public void setArgumentResolvers(RequestMappingHandlerAdapter adapter) {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();
resolvers.add(new CustomPrincipalArgumentResolver());
resolvers.addAll(adapter.getArgumentResolvers().getResolvers());
adapter.setArgumentResolvers(resolvers);
}
}
Run Code Online (Sandbox Code Playgroud)
您还可以扩展WebMvcConfigurationSupport而不是使用@EnableWebMvc以确保首先使用HandlerMethodArgumentResolver.例如:
@Configuration
public class WebConfiguration extends WebMvcConfigurationSupport {
...
@Bean
@Override
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter()();
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();
resolvers.add(new CustomPrincipalArgumentResolver());
resolvers.addAll(adapter.getArgumentResolvers().getResolvers());
adapter.setArgumentResolvers(resolvers);
return adapter;
}
}
Run Code Online (Sandbox Code Playgroud)
我知道这是一个老问题,但由于它在搜索注入 Principal 时在 Google 上名列前茅,因此我将发布 2020 年更新:
从 Spring Security 4.0 开始,您可以简单地将一个注入@AuthenticationPrincipal到您的控制器方法中:
@RequestMapping(value = "/")
public ResponseEntity<List<Conversation>> listAfter(@AuthenticationPrincipal UserPrincipal user){
// implementation
}
Run Code Online (Sandbox Code Playgroud)
这将是开箱即用的,不需要额外的配置。
| 归档时间: |
|
| 查看次数: |
6836 次 |
| 最近记录: |