没有用户名密码和UserDetailsS​​ervice接口的@PreAuthorize

时间:2020-06-10 22:22:48

标签: spring-boot spring-security jwt authority

这就是场景。

我有登录API,它将jwt令牌返回给客户端,该API具有注释@PermitAll

然后我有另一个受保护的API,只有在验证jwt令牌后才能访问。发送对安全API的请求的方式是,将Authorization参数添加到标头中并带有jwt令牌的值,并将该请求传递给安全API。请注意,此API的authorization typeNo Auth。我编写了一个JwtRequestFilter extends OncePerRequestFilter类,在其中我拦截了请求,提取了令牌,对其进行了验证,并返回了适当的响应,一切正常。但是有一个问题,问题是控制器类的方法顶部有@PreAuthorize("hasAuthority('RANDOM_PRIV_1')")批注,并且JwtRequestFilter并没有对其进行验证,因此实际上不应该如此这样做不是它的工作。

我知道list of GrantedAuthorities被传递到UserDetailsService的实现中,并由方法loadUserByUsername进行了验证。但是我不能使用此接口的实现,原因是,仅当authorization typeBasic Auth且不使用这种类型的身份验证时才调用其实现。

所以我要寻找的是一个接口/类,可以验证GrantedAuthorities; UserDetailsService对其进行验证的方式。

如果没有这样的功能,那么我有第二个工作选择,扩展HandlerInterceptorAdapter,在preHandle中,我验证令牌并验证与用户关联的GrantAuthorities并验证(manually)针对方法中存在的PreAuthorize注释。这对我有用,但我仍在寻找更清洁的解决方案。

P.S:我也通过了此链接,但是没有找到任何有用的信息。 Spring boot basic authentication without UserDetailsService method

任何帮助将不胜感激。

1 个答案:

答案 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批注验证与之匹配。