在上一篇中,我们介绍了认证服务器的搭建,由于我们没有自己的客户端回调地址,在测试过程中,我们是使用http://www.baidu.com作为回调地址,获取到授权码code后,再使用postman去获取令牌信息的。在本篇中,我们将搭建自己的客户端,实现连贯的令牌获取操作, 操作流程如下。
场景类比
假设我们公司的web平台产品支持微信登录,那么对于微信平台来说,我们的web平台就是客户端(第三方),那么,首先我们就得需要在微信开发者平台中注册客户端信息,例如:申请客户端id(client_id,微信平台叫appId)、密钥(secret)、配置授权码回调地址等。上一篇我们搭建的工程spring-oauth-server就类似微信平台的认证服务器,我们接下来要搭建的客户端工程叫spring-oauth-client就类似公司的web平台。
客户端搭建
在spring-oauth-parent父工程下,创建spring-oauth-client子工程,添加spring-boot-starter-oauth2-client依赖,由于此处与Spring Authorization Server框架无关,可不用必须使用SpringBoot3,但为了版本统一,在此还是继续使用父工程中的SpringBoot3。
pom.xml添加依赖如下。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.oauth</groupId>
<artifactId>spring-oauth-parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>spring-oauth-client</artifactId>
<name>客户端</name>
<dependencies>
<!--spring-boot-starter-oauth2-client-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<!--spring-boot-starter-web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
application.yml配置如下
server:
port: 9001
logging:
level:
org.springframework.security: trace
spring:
application:
name: spring-oauth-client
security:
oauth2:
client:
provider:
#认证服务器信息
oauth-server:
#授权地址
issuer-uri: http://spring-oauth-server:9000
authorizationUri: ${spring.security.oauth2.client.provider.oauth-server.issuer-uri}/oauth2/authorize
#令牌获取地址
tokenUri: ${spring.security.oauth2.client.provider.oauth-server.issuer-uri}/oauth2/token
registration:
messaging-client-oidc:
#认证提供者,标识由哪个认证服务器进行认证,和上面的oauth-server进行关联
provider: oauth-server
#客户端名称
client-name: web平台
#客户端id,从认证平台申请的客户端id
client-id: web-client-id
#客户端秘钥
client-secret: secret
#客户端认证方式
client-authentication-method: client_secret_basic
#使用授权码模式获取令牌(token)
authorization-grant-type: authorization_code
#回调地址,接收认证服务器回传code的接口地址,之前我们是使用http://www.baidu.com代替
redirect-uri: http://spring-oauth-client:9001/login/oauth2/code/messaging-client-oidc
scope:
- profile
- openid
注意:上面配置中出现两个域名,分别是spring-oauth-client、spring-oauth-server,因为我是在同一台机器上进行启动客户端和认证服务器的,ip都是127.0.0.1,在ip相同的情况下,会出现cookie覆盖的情形,这会导致认证服务器重定向到客户端地址时会出现[authorization_request_not_found]异常,为解决这个问题,本人在C:\Windows\System32\drivers\etc目录下的hosts文件添加了一行IP域名映射,即127.0.0.1 spring-oauth-client spring-oauth-server。
启动类如下。
@SpringBootApplication
public class SpringOauthClientApplication {
public static void main(String[] args) {
SpringApplication.run(SpringOauthClientApplication.class,args);
}
}
客户端信息表oauth2_registered_client增加下面一条客户端记录。
INSERT INTO `oauth-server`.`oauth2_registered_client` (`id`, `client_id`, `client_id_issued_at`, `client_secret`, `client_secret_expires_at`, `client_name`, `client_authentication_methods`, `authorization_grant_types`, `redirect_uris`, `post_logout_redirect_uris`, `scopes`, `client_settings`, `token_settings`) VALUES ('3eacac0e-0de9-4727-9a64-6bdd4be2ee1g', 'web-client-id', '2023-07-12 07:33:42', '$2a$10$.J0Rfg7y2Mu8AN8Dk2vL.eBFa9NGbOYCPOAFEw.QhgGLVXjO7eFDC', NULL, 'web平台', 'client_secret_basic', 'refresh_token,authorization_code', 'http://spring-oauth-client:9001/login/oauth2/code/messaging-client-oidc', 'http://127.0.0.1:9000/', 'openid,profile', '{\"@class\":\"java.util.Collections$UnmodifiableMap\",\"settings.client.require-proof-key\":false,\"settings.client.require-authorization-consent\":true}', '{\"@class\":\"java.util.Collections$UnmodifiableMap\",\"settings.token.reuse-refresh-tokens\":true,\"settings.token.id-token-signature-algorithm\":[\"org.springframework.security.oauth2.jose.jws.SignatureAlgorithm\",\"RS256\"],\"settings.token.access-token-time-to-live\":[\"java.time.Duration\",300.000000000],\"settings.token.access-token-format\":{\"@class\":\"org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat\",\"value\":\"self-contained\"},\"settings.token.refresh-token-time-to-live\":[\"java.time.Duration\",3600.000000000],\"settings.token.authorization-code-time-to-live\":[\"java.time.Duration\",300.000000000],\"settings.token.device-code-time-to-live\":[\"java.time.Duration\",300.000000000]}');
新建AuthenticationController类,代码如下。
@RestController
public class AuthenticationController {
@GetMapping("/token")
@ResponseBody
public OAuth2AuthorizedClient token(@RegisteredOAuth2AuthorizedClient OAuth2AuthorizedClient oAuth2AuthorizedClient) {
return oAuth2AuthorizedClient;
}
}
客户端工程结构如下。
客户端测试
启动认证服务器和客户端服务,浏览器输入http://spring-oauth-client:9001/token地址发起接口访问。
此时我们看到,浏览器地址已被重定向到认证服务器http://spring-oauth-server:9000/login中被要求进行登录,
输入用户在认证服务器的用户名:user,密码:123456,则跳转到认证服务器授权页面,
勾选授权信息profile,点击提交按钮,则返回如下结果。
此时我们看到了浏览器中的地址为http://spring-oauth-client:9001/token?continue,且返回了客户端及token信息。也看到了认证服务器将授权码拼接到了回调地址http://spring-oauth-client:9001/login/oauth2/code/messaging-client-oidc中传给客户端。
页面json数据如下。
{
"clientRegistration":{
"registrationId":"messaging-client-oidc",
"clientId":"web-client-id",
"clientSecret":"secret",
"clientAuthenticationMethod":{
"value":"client_secret_basic"
},
"authorizationGrantType":{
"value":"authorization_code"
},
"redirectUri":"http://spring-oauth-client:9001/login/oauth2/code/messaging-client-oidc",
"scopes":[
"profile",
"openid"
],
"providerDetails":{
"authorizationUri":"http://spring-oauth-server:9000/oauth2/authorize",
"tokenUri":"http://spring-oauth-server:9000/oauth2/token",
"userInfoEndpoint":{
"uri":"http://spring-oauth-server:9000/userinfo",
"authenticationMethod":{
"value":"header"
},
"userNameAttributeName":"sub"
},
"jwkSetUri":"http://spring-oauth-server:9000/oauth2/jwks",
"issuerUri":"http://spring-oauth-server:9000",
"configurationMetadata":{
"authorization_endpoint":"http://spring-oauth-server:9000/oauth2/authorize",
"token_endpoint":"http://spring-oauth-server:9000/oauth2/token",
"introspection_endpoint":"http://spring-oauth-server:9000/oauth2/introspect",
"revocation_endpoint":"http://spring-oauth-server:9000/oauth2/revoke",
"device_authorization_endpoint":"http://spring-oauth-server:9000/oauth2/device_authorization",
"issuer":"http://spring-oauth-server:9000",
"jwks_uri":"http://spring-oauth-server:9000/oauth2/jwks",
"scopes_supported":[
"openid"
],
"response_types_supported":[
"code"
],
"grant_types_supported":[
"authorization_code",
"client_credentials",
"refresh_token",
"urn:ietf:params:oauth:grant-type:device_code"
],
"token_endpoint_auth_methods_supported":[
"client_secret_basic",
"client_secret_post",
"client_secret_jwt",
"private_key_jwt"
],
"introspection_endpoint_auth_methods_supported":[
"client_secret_basic",
"client_secret_post",
"client_secret_jwt",
"private_key_jwt"
],
"revocation_endpoint_auth_methods_supported":[
"client_secret_basic",
"client_secret_post",
"client_secret_jwt",
"private_key_jwt"
],
"request_uri_parameter_supported":true,
"subject_types_supported":[
"public"
],
"userinfo_endpoint":"http://spring-oauth-server:9000/userinfo",
"end_session_endpoint":"http://spring-oauth-server:9000/connect/logout",
"id_token_signing_alg_values_supported":[
"RS256"
]
}
},
"clientName":"web平台"
},
"principalName":"user",
"accessToken":{
"tokenValue":"eyJraWQiOiIyYzZlOTdkNi01NzhjLTQ3NWYtYmYzNy1lMDljODY3OWUyYzAiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c2VyIiwiYXVkIjoid2ViLWNsaWVudC1pZCIsIm5iZiI6MTY4OTI0NTM2NSwic2NvcGUiOlsib3BlbmlkIiwicHJvZmlsZSJdLCJpc3MiOiJodHRwOi8vc3ByaW5nLW9hdXRoLXNlcnZlcjo5MDAwIiwiZXhwIjoxNjg5MjQ1NjY1LCJpYXQiOjE2ODkyNDUzNjV9.dBIkteklddxt6BFFalMi11fjk1t_9gA034jeO3vbcGPadCjpM46AxUAolH3mD98d-mCVlwzl1enFtFfvHdJEBB4LbGMwBfvDHUXK6ODk3rNwU_I8pIOq2AG9cErSnnRBMSAVsz421UnXL_bcITM1iYSZmhkiRxyg4JwZLN1h-4H35RsjqU1IBYappPNPeH7P7DzbIQ10M58gieajyII0oU90ksgPf4J3sy3FMQG29WAe1Mtul5W1lP-eLhTYStnHH8FJxFIrJMO2kTv2T7pP2OUDBIBSxU7KORACVhr74xWmIzuMa9Ue3anI34JIn4hicSsnoq-EmHv03pFSRlKbYQ",
"issuedAt":"2023-07-13T10:49:25.091674300Z",
"expiresAt":"2023-07-13T10:54:24.091674300Z",
"tokenType":{
"value":"Bearer"
},
"scopes":[
"openid",
"profile"
]
},
"refreshToken":{
"tokenValue":"1Ed1_Y8vrxGjnz-v-9CNG6-iP1fyPOo1bll3UMhNNFzY5R8ODENRIiBfqoZHKx4t9eg-B43aOmoO-x8ca8UdQqwQB35i40CHhp4GsekkyDYQ51F5hUUeM_0LdQYlI9sC",
"issuedAt":"2023-07-13T10:49:25.091674300Z",
"expiresAt":null
}
}
注意:在上面的测试中,我们通过OAuth2AuthorizedClient对象获取到客户端和令牌相关的信息,然后直接返回给前端页面,在实际应用中,要根据实际需要,返回适当的字段。
总结
本文简单介绍了oauth2客户端的搭建及测试,客户端的主要职责是识别用户操作是否有身份认证,已认证,则放行,未认证,则拒绝或引导到认证服务器进行认证。到此,一个简单的客户端就此搭建完成。
标签:Spring,Server,token,client,spring,oauth,server,Authorization,客户端 From: https://blog.51cto.com/u_15268610/6779127