OAuth2客户端根据是否能够与授权服务器进行安全认证,可以分为机密型(Confidential)和公开型(Public)。机密类型本身会有密码凭证,比如web服务器后台程序;而public类型是没有密码凭证的,大多数纯浏览器前端应用或者手机客户端应用都属于这种类型。无论哪种方式,它们都有一个客户端ID(client_id)。OAuth2客户端认证客户端在执行OAuth2授权的敏感过程(相关过程包括token请求、token自省请求、token撤销请求)必须使用授权服务器进行客户端认证,以保证客户端不会中途被认证Changeling。客户端认证方式目前客户端认证方式有以下几种:之前的GiteeDEMO使用过时的POST方式;微信DEMO采用非OAuth2标准方式;SpringAuthorizationServer目前相关的DEMO使用的是client_secret_basic方法。剩下的方法中,用的最多的是client_secret_jwt和private_key_jwt。这两种方式可以很好的保护客户端的认证信息,更加安全。目前SpringSecurity和SpringAuthorizationServer都支持这两种方式。client_secret_jwtclient_secret_jwt方法是OAuth2客户端使用自己的key作为HmacSHA256算法的key生成一个SecretKey:byte[]pin=clientSecret.getBytes(StandardCharsets.UTF_8);SecretKeySpecsecretKey=newSecretKeySpec(pin,"HmacSHA256");然后通过SecretKey生成一个携带OAuth2客户端信息的JWT,携带在授权码请求Token链接中,以便授权服务器对客户端进行认证。请求的消息是:POST/oauth2/tokenHTTP/1.1Host:oauth2_client.felord.cnContent-Type:application/x-www-form-urlencodedgrant_type=authorization_code&code=n0esc3NRze7LTCu7iYzS6a5acc3f0ogp4&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&client_assertion=你的JWT授权服务器接收到客户端的请求,通过OAuth2client_secret解码并验证JWT对客户端进行认证。该方法可以很好的保护非HTTPS环境下client_secret的传输。这里的OAuth2客户端密钥(client_secret)位长必须大于等于256。private_key_jwtprivate_key_jwt和client_secret_jwt的唯一区别是生成JWT的方式不同。这样OAuth2客户端就不需要client_secret了,只需要配置一对RSA或者EC密钥,通过密钥生成JWT,还需要提供公钥给授权服务器,一般是一个jwkSetUrl。这个方法的细节在胖哥的专栏[1]中的JOSE规范[2]中已经有详细的解释,这里不再赘述。这种方式可以让客户端的认证信息更安全的传输,是我个人比较喜欢的方式。tls_client_auth更高级,嵌入了TLS安全层,在HTTP协议级别对OAuth2客户端进行身份验证,它涉及的证书来自受信任的CA。这种方式基本上脱离了应用层,是一种非侵入式的方式。self_signed_tls_client_auth也在TLS安全层,但它使用自签名的X.509证书。综上所述,市面上的教程大多只提到过时的POST方法和client_secret_basic和client_secret_post,很少涉及后五种。胖哥会详细实现private_key_jwt和client_secret_jwt。详情请订阅我的SpringSecurityOAuth2专栏。这些OAuth2客户端认证方式在不同的场景下有不同的优势,您可以根据不同的安全级别选择不同的OAuth2客户端认证方式。参考文献[1]胖哥专栏:https://blog.csdn.net/qq_35067322/category_11691173.html[2]JOSE规范:https://felord.blog.csdn.net/article/details/123540550
