7 客户端认证方式 之 client_secret_jwt

本文详细介绍了OAuth2中client_secret_jwt的认证方式,包括原理、步骤和代码实现。首先,客户端使用HMAC算法和client_secret生成JWT,然后在授权请求中携带JWT。授权服务器通过相同算法和secret验证JWT,从而认证客户端。文中还展示了Postman测试和curl命令示例,完整呈现了整个认证流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这篇文章来讲讲 client_secret_jwt 方式。

client_secret_jwt

client_secret_jwt方式就是利用 JWT 进行认证。请求方和授权服务器,两者都知道客户端的 client_secret,通过相同的 HMAC 算法(对称签名算法)去加签和验签 JWT ,可以达到客户端认证的目的。
请求方 通过 HMAC算法,以 client_secret 作为密钥,将客户端信息加签生成 JWT
授权服务器 使用相同的 HMAC算法和client_secret,对请求方的 JWT 进行验签以认证客户端。

了解 JWT 的签名算法

示例

请求方传参:

  • client_id
  • client_assertion_type:固定值 urn:ietf:params:oauth:client-assertion-type:jwt-bearer
  • client_assertion:client生成的jwt

环境准备

授权服务器

同样的,基于 快速搭建一个授权服务器 文章中的示例,修改 SecurityConfigurationregisteredClientRepository() 方法,如下:

    @Bean
    public RegisteredClientRepository registeredClientRepository() {
        RegisteredClient registeredClient3 = RegisteredClient.withId(UUID.randomUUID().toString())
                .clientId("client3")
                // jwt方式验证,密码作为签名算法的密钥,不能配前缀!
                .clientSecret("01234567890123456789012345678912")
                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_JWT)
                .clientSettings(ClientSettings.builder()
                        // JWT 方式必须配置,确定jwt的签名算法(CLIENT_SECRET_JWT 方式使用 MacAlgorithm(对称加密算法),密钥为client_secret)
                        .tokenEndpointAuthenticationSigningAlgorithm(MacAlgorithm.HS256)
                        .build())
                .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
                .build();

        return new InMemoryRegisteredClientRepository(registeredClient3 );
    }

测试

  1. 生成 JWT
public class ClientJwtTest {
    public static void main(String[] args) throws JOSEException {
        String clientId = "client3";
        String clientSecret = "01234567890123456789012345678912";

        // 至少以下四项信息
        JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
                // 主体:固定clientId
                .subject(clientId)
                // 发行者:固定clientId
                .issuer(clientId)
                // 授权中心的地址
                .audience("http://localhost:9000")
                // 过期时间
                .expirationTime(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24))
                .build();

        String jwt = hmacSign(claimsSet, clientSecret);
        System.out.println(jwt);
        // eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJjbGllbnQxIiwic3ViIjoiY2xpZW50MSIsImF1ZCI6Imh0dHA6XC9cL2xvY2FsaG9zdDo5MDAwIiwiZXhwIjoxNjYxNjk5ODAzfQ.xpv_8w_R8LTZFID3uoQPn3CyQK_Bli3G-WTmrSrwayE
    }

    /**
     * 使用 HMAC 算法加签生成jwt
     */
    private static String hmacSign(JWTClaimsSet claimsSet, String secret) throws JOSEException {
        SecretKeySpec secretKeySpec = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
        JWSSigner signer = new MACSigner(secretKeySpec);

        SignedJWT signedJWT = new SignedJWT(new JWSHeader(JWSAlgorithm.HS256), claimsSet);
        signedJWT.sign(signer);
        String token = signedJWT.serialize();
        return token;
    }

}
  1. 使用Postman测试,在 Body栏,填入’client_idclient_assertion_typeclient_assertiongrant_type’,发送请求。
    在这里插入图片描述
    可以看到,使用此方式能成功获取到 access_token,说明授权服务器确实支持此认证方式。
  • 相应的curl命令如下:
curl --location --request POST 'localhost:9000/oauth2/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'client_id=client3' \
--data-urlencode 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' \
--data-urlencode 'client_assertion=eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJjbGllbnQzIiwic3ViIjoiY2xpZW50MyIsImF1ZCI6Imh0dHA6Ly9sb2NhbGhvc3Q6OTAwMCIsImV4cCI6MTY3Mjk5OTgwM30.Cu0JobiFyhyn0mS4rc8pMogI5eOE8uM84v8w5011Gkg'

源码分析

JwtClientAssertionAuthenticationConverter

从请求中解析出 client_idclient_assertion_typeclient_assertion 参数。

JwtClientAssertionAuthenticationProvider

JwtClientAssertionAuthenticationProvider 的核心就是对JWT进行解析和验证。
核心流程如下:

  1. 使用请求携带的 clientId 查询客户端信息,若不存在则直接抛出异常。
  2. 创建解析 JWT 的核心类 JwtDecoder
  3. 解析 JWT,并验签
    在这里插入图片描述

解析:
我们在文章开头就说到 授权服务器 需要使用相同的 HMAC算法和client_secret,对请求方的 JWT 进行验签以认证客户端。事实也确实如此,一路跟踪创建 JwtDecoder 的代码就会发现,JwtDecoder 的创建过程就会用到客户端的配置(签名算法、密钥)
在这里插入图片描述
创建完 JwtDecoder 之后,就要执行解析和验签了:jwtDecoder.decode(clientAuthentication.getCredentials().toString());
从上面可以看出,jwtDecoder 的实际类型为 NimbusJwtDecoder,其解析JWT和验签逻辑如下:
在这里插入图片描述
到这,已经梳理完整个主干流程。另外像比如一些规范性的校验逻辑,读者就可以自行去扩展了解。

下集预告:客户端认证方式 之 private_key_jwt,敬请期待。


end

<think>好的,我现在需要帮助用户解决关于OAuth密码授权流程生成token的问题。用户希望得到请求示例和相关配置的说明,具体涉及client_id、client_secret、grant_type、username和password的使用。首先,我应该回忆OAuth 2.0密码授权模式的基本流程,然后结合提供的引用内容来构建回答。 根据引用[1],Laravel中使用密码授权模式需要提交特定的参数,包括client_id、client_secret、grant_type等。用户提供的示例代码显示了一个POST请求到/oauth/token端点,参数以form_params形式传递。这可以作为请求示例的基础。 接下来,引用[2]和[3]提到了验证流程,包括通过client_id查询客户端信息,以及授权服务器如何验证这些参数。需要强调client_id和client_secret的作用,即客户端应用在授权服务器注册后获得的凭证,确保请求的合法性。 引用[4]和[5]讨论了不同客户端认证方法,比如client_secret_jwt,但用户的问题是关于密码授权模式,所以主要关注client_secret_basic或client_secret_post。在请求示例中,Authorization头使用Basic认证,这是将client_id和client_secret进行Base64编码后的结果,如引用[3]中的示例所示。 用户可能需要知道如何配置客户端和用户信息。根据引用[5],oauth_client_details表存储了客户端的详细信息,如client_id、client_secret、权限范围等。因此,配置步骤应包括在数据库中注册客户端,并确保用户存在且有效。 此外,需要解释每个参数的意义:grant_type必须设为password,client_id和client_secret客户端凭证,username和password是资源所有者的凭据。还要提到scope参数可选,用于限制令牌权限。 在生成请求示例时,应展示正确的HTTP方法和头部,如Content-Type和Authorization头。同时,需要指出可能的响应字段,如access_token、token_type、expires_in等,如引用[2]提到的响应流返回的内容。 安全注意事项也很重要,比如使用HTTPS、保护client_secret、避免明文存储密码等,这些在引用中虽然没有直接提到,但属于OAuth最佳实践,应该包含在回答中。 最后,根据用户要求生成相关问题,考虑常见的后续问题,如刷新令牌、客户端注册步骤、安全措施、不同授权模式比较等,这些能帮助用户进一步理解相关主题。 总结回答结构:先概述密码授权流程,给出配置步骤和请求示例,解释参数,最后注意事项和相关问题。</think>### OAuth密码授权流程生成Token的配置与请求示例 #### 一、核心流程说明 OAuth密码授权模式(Resource Owner Password Credentials Grant)允许客户端直接使用**用户名/密码**换取访问令牌,适用于受信任的客户端(如第一方应用)[^1][^3]。 #### 二、配置步骤 1. **注册客户端** 在授权服务器的`oauth_client_details`表中创建客户端记录,包含以下关键字段[^3][^5]: ```sql client_id: 'my-client-id' -- 客户端唯一标识 client_secret: 'my-client-secret' -- 客户端密钥 authorized_grant_types: 'password' -- 授权类型需包含password scope: 'read write' -- 权限范围 ``` 2. **用户账户验证** 确保用户凭据(username/password)在系统中有效,且客户端具备访问权限[^2][^5]。 --- #### 三、HTTP请求示例 ```http POST /oauth/token HTTP/1.1 Host: auth-server.com Authorization: Basic base64(client_id:client_secret) Content-Type: application/x-www-form-urlencoded grant_type=password&[email protected]&password=myPassword&scope=read ``` * **参数说明**: - `Authorization: Basic`头:将`client_id:client_secret`进行Base64编码(如`bXktY2xpZW50LWlkOm15LWNsaWVudC1zZWNyZXQ=`)[^3][^4] - `grant_type=password`:固定参数声明授权类型 - `username/password`:资源所有者的登录凭证[^2] - `scope`(可选):限制令牌权限范围[^5] * **成功响应**: ```json { "access_token": "eyJhbGciOi...", "token_type": "bearer", "expires_in": 3600, "refresh_token": "def50200...", "scope": "read" } ``` --- #### 四、安全注意事项 1. **仅限受信任客户端**:此模式需直接处理用户密码,需确保客户端代码安全[^1] 2. **强制HTTPS**:防止凭证在传输中被截获 3. **避免存储明文密码**:客户端不应保存用户密码[^2] 4. **定期轮换密钥**:更新`client_secret`降低泄露风险[^5] ---
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值