微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Spring Boot OAuth2资源服务器:库如何在没有公共密钥的情况下验证JWT令牌?

如何解决Spring Boot OAuth2资源服务器:库如何在没有公共密钥的情况下验证JWT令牌?

我有以下配置最少的Spring Boot应用程序

application.properties

server.port=8081
spring.security.oauth2.resourceserver.jwt.issuer-uri = http://localhost:8080/auth/realms/master

pom.xml

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.nurgasemetey</groupId>
    <artifactId>springboot-keycloak</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-keycloak</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
        </dependency>

控制器

@RestController
@RequestMapping("/users")
public class UsersController {
    @GetMapping("/status/check")
    public String status(@AuthenticationPrincipal Jwt principal) {
        return "working";
    }
}

就像我在代码中看到的那样,Spring Boot Oauth2似乎没有使用公钥:

OAuth2ResourceServerProperties

/**
         * JSON Web Key URI to use to verify the JWT token.
         */
        private String jwkSetUri;

        /**
         * JSON Web Algorithm used for verifying the digital signatures.
         */
        private String jwsAlgorithm = "RS256";

        /**
         * URI that can either be an OpenID Connect discovery endpoint or an OAuth 2.0
         * Authorization Server Metadata endpoint defined by RFC 8414.
         */
        private String issuerUri;

        /**
         * Location of the file containing the public key used to verify a JWT.
         */
        private Resource publicKeyLocation;

但是我没有给出publicKeyLocation,但是应用可以在没有公共密钥的情况下进行验证。

内部使用JwtIssuerValidatorJwtTimestampValidator验证程序。

另一方面,对于express-jwt,它需要公共密钥才能进行离线验证

const express = require('express');
const jwt = require('express-jwt');
const app = express();
const secret = 'secret';
const fs = require('fs');
var publicKey = fs.readFileSync('public.pub');


app.get('/protected',jwt({ secret: publicKey,algorithms: ['RS256'] }),(req,res) => {
  res.send('protected');
})
app.listen(3000,() => console.log('server started'));

Spring Boot Oauth如何在没有公共密钥的情况下进行验证?

解决方法

自我答案。

首先,似乎http://localhost:8080/auth/realms/master公开了公钥。就像在Generate JWT Token in Keycloak and get public key to verify the JWT token on a third party platform - Stack Overflow和@ThomasKåsene对这个问题的评论中所说的那样

其次,我挖掘了spring boot oauth2代码并偶然发现了该代码

ReactiveOAuth2ResourceServerJwkConfiguration

@Bean
        @Conditional(IssuerUriCondition.class)
        ReactiveJwtDecoder jwtDecoderByIssuerUri() {
            return ReactiveJwtDecoders.fromIssuerLocation(this.properties.getIssuerUri());
        }

JwtDecoderProviderConfigurationUtils

private static Map<String,Object> getConfiguration(String issuer,URI... uris) {
        String errorMessage = "Unable to resolve the Configuration with the provided Issuer of " +
                "\"" + issuer + "\"";
        for (URI uri : uris) {
            try {
                RequestEntity<Void> request = RequestEntity.get(uri).build();
                ResponseEntity<Map<String,Object>> response = rest.exchange(request,typeReference);
                Map<String,Object> configuration = response.getBody();

                if (configuration.get("jwks_uri") == null) {
                    throw new IllegalArgumentException("The public JWK set URI must not be null");
                }

                return configuration;
            } catch (IllegalArgumentException e) {
                throw e;
            } catch (RuntimeException e) {
                if (!(e instanceof HttpClientErrorException &&
                        ((HttpClientErrorException) e).getStatusCode().is4xxClientError())) {
                    throw new IllegalArgumentException(errorMessage,e);
                }
                // else try another endpoint
            }
        }
        throw new IllegalArgumentException(errorMessage);
    }

似乎是从issuer-uri中给出的application.properties获取公钥的。提取后,它将使用提取的公钥验证jwt令牌。

要测试

关闭您的jwt提供程序,以我的情况为例,并运行spring boot应用程序,然后它给出

Caused by: java.lang.IllegalArgumentException: Unable to resolve the Configuration with the provided Issuer of "http://localhost:8080/auth/realms/master"

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。