所以,这里的情况是这样的。
我有一个登录API,它返回jwt token给客户端,这个API有注解 @PermitAll
.
然后,我有另一个API是安全的,只有在验证jwt token后才能访问。向安全的API发送请求的方式是这样的 Authorization
参数在头中加入jwt token的值,然后将请求传递给安全API。请注意 authorization type
这个API的是 No Auth
. 我写了一个类 JwtRequestFilter extends OncePerRequestFilter
在其中,我拦截了请求,提取了令牌,验证了令牌,返回了相应的响应,一切都很顺利。但是有一个问题,这个问题就是有 @PreAuthorize("hasAuthority('RANDOM_PRIV_1')")
注解在控制器类中方法的顶部,并且它没有被控制器类中的 JwtRequestFilter
而且实际上它不应该这样做,因为这不是它的工作。
我知道 list of GrantedAuthorities
传递给执行的 UserDetailsService
并通过方法进行验证 loadUserByUsername
. 但我不能使用这个接口的实现,原因是,它的实现只有在当 authorization type
是 Basic Auth
而我没有使用这种类型的认证。
因此,我正在寻找一个接口类,我可以通过它来验证 GrantedAuthorities
的方式来验证。UserDetailsService
.
如果没有这样的功能,那么我有第二种工作方案,扩展了 HandlerInterceptorAdapter
并在 preHandle
我验证了token,也验证了与用户相关联的授予权限,并验证了(manually)
方法上的PreAuthorize注解。这对我来说是有效的,但我仍然在寻找更干净的解决方案。
P.S: 我也看了这个链接,但没有找到任何有用的信息。没有UserDetailsService方法的Spring引导基本认证。.
任何帮助将是非常感激的。
如果你想使用jwt来验证请求,那么你可以使用Spring Security对它的内置支持。
你仍然需要自己创建jwt,但是对于处理jwt并将其转化为Granted Authorities,你可以这样做。
http
.authorizeRequests(...
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(jwt -> {})
);
这告诉Spring Security要建立一个过滤器(BearerTokenAuthenticationFilter
)来提取token并进行处理,可能和你的 JwtRequestFilter
.
由于您是在本地创建JWT(而不是使用授权服务器等),您需要告诉Spring Security如何验证令牌。这通常是通过对称密钥完成的。
@Bean
JwtDecoder jwtDecoder() {
return NimbusJwtDecoder.withSecretKey(...).build();
}
最后,关于你提出的授权问题: 例如,假设您提到的授权(RANDOM_PRIV_1
)在你的JWT中被列为作用域,你可以构造一个 JwtAuthenticationConverter
豆。
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会对其进行处理,提取权限,并验证它们是否与使用JWT的权限相匹配。@PreAuthorize
注释。