这就是场景。
我有登录API,它将jwt令牌返回给客户端,该API具有注释@PermitAll
。
然后我有另一个受保护的API,只有在验证jwt令牌后才能访问。发送对安全API的请求的方式是,将Authorization
参数添加到标头中并带有jwt令牌的值,并将该请求传递给安全API。请注意,此API的authorization type
为No Auth
。我编写了一个JwtRequestFilter extends OncePerRequestFilter
类,在其中我拦截了请求,提取了令牌,对其进行了验证,并返回了适当的响应,一切正常。但是有一个问题,问题是控制器类的方法顶部有@PreAuthorize("hasAuthority('RANDOM_PRIV_1')")
批注,并且JwtRequestFilter
并没有对其进行验证,因此实际上不应该如此这样做不是它的工作。
我知道list of GrantedAuthorities
被传递到UserDetailsService
的实现中,并由方法loadUserByUsername
进行了验证。但是我不能使用此接口的实现,原因是,仅当authorization type
为Basic Auth
且不使用这种类型的身份验证时才调用其实现。
所以我要寻找的是一个接口/类,可以验证GrantedAuthorities
; UserDetailsService
对其进行验证的方式。
如果没有这样的功能,那么我有第二个工作选择,扩展HandlerInterceptorAdapter
,在preHandle
中,我验证令牌并验证与用户关联的GrantAuthorities并验证(manually)
针对方法中存在的PreAuthorize注释。这对我有用,但我仍在寻找更清洁的解决方案。
P.S:我也通过了此链接,但是没有找到任何有用的信息。 Spring boot basic authentication without UserDetailsService method。
任何帮助将不胜感激。
答案 0 :(得分:0)
如果您想使用JWT对请求进行身份验证,则可以使用Spring Security的内置支持。
您仍然需要自己创建JWT,但是要处理JWT并将其转变为授予的权限,您可以执行以下操作:
http
.authorizeRequests(...
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(jwt -> {})
);
这告诉Spring Security站起来一个过滤器(BearerTokenAuthenticationFilter
),该过滤器提取并处理令牌,可能很像您的JwtRequestFilter
。
由于要在本地创建JWT(例如,而不是使用Authorization Server),因此需要告诉Spring Security如何验证令牌。通常使用对称密钥来完成此操作:
@Bean
JwtDecoder jwtDecoder() {
return NimbusJwtDecoder.withSecretKey(...).build();
}
最后,关于您的授权问题。例如,假定您提到的权限(RANDOM_PRIV_1
)被列为JWT的作用域,则可以构造一个JwtAuthenticationConverter
bean:
JwtAuthenticationConverter jwtAuthenticationConverter() {
JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
converter.setJwtGrantedAuthoritiesConverter(jwt -> {
Collection<String> scopes = jwt.getClaim("scope");
return scopes.stream()
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
});
return converter;
}
然后将其添加到DSL:
http
.authorizeRequests(...
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(jwt -> jwt
.jwtAuthenticationConverter(jwtAuthenticationConverter())
)
);
然后,当请求中出现JWT时,Spring Security将对其进行处理,提取权限,并使用@PreAuthorize
批注验证与之匹配。