From 65ee56c81194209d827a592a9224c3c2b7ec3a2b Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 15 May 2022 18:32:34 +0800 Subject: [PATCH] 完成 oauth2 check-token 校验 token 的实现 --- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2Controller.http | 44 -------------------------------------------- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.http | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.java | 29 ++++++++++++++++++++++++----- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/open/OAuth2OpenAccessTokenRespVO.java | 2 +- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/open/OAuth2OpenCheckTokenRespVO.java | 40 ++++++++++++++++++++++++++++++++++++++++ yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/oauth2/OAuth2OpenConvert.java | 11 ++++++++++- yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/security/config/SecurityConfiguration.java | 2 +- 7 files changed, 125 insertions(+), 52 deletions(-) delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2Controller.http create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.http create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/open/OAuth2OpenCheckTokenRespVO.java diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2Controller.http b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2Controller.http deleted file mode 100644 index 691ed9e..0000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2Controller.http +++ /dev/null @@ -1,44 +0,0 @@ -### 请求 /system/oauth2/authorize + token 接口 => 成功 -POST {{baseUrl}}/system/oauth2/authorize -Content-Type: application/x-www-form-urlencoded -Authorization: Bearer {{token}} -tenant-id: {{adminTenentId}} - -response_type=token&client_id=default&scope={"user_info": true}&redirect_uri=https://www.iocoder.cn&auto_approve=true - -### 请求 /system/oauth2/authorize + code 接口 => 成功 -POST {{baseUrl}}/system/oauth2/authorize -Content-Type: application/x-www-form-urlencoded -Authorization: Bearer {{token}} -tenant-id: {{adminTenentId}} - -response_type=code&client_id=default&scope={"user_info": true}&redirect_uri=https://www.iocoder.cn&auto_approve=true - -### 请求 /system/oauth2/token + code 接口 => 成功 -POST {{baseUrl}}/system/oauth2/token -Content-Type: application/x-www-form-urlencoded -Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw== -tenant-id: {{adminTenentId}} - -grant_type=authorization_code&redirect_uri=https://www.iocoder.cn - -### 请求 /system/oauth2/token + password 接口 => 成功 -POST {{baseUrl}}/system/oauth2/token -Content-Type: application/x-www-form-urlencoded -Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw== -tenant-id: {{adminTenentId}} - -grant_type=password&username=admin&password=admin123&scope=user_info - -### 请求 /system/oauth2/token + refresh_token 接口 => 成功 -POST {{baseUrl}}/system/oauth2/token -Content-Type: application/x-www-form-urlencoded -Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw== -tenant-id: {{adminTenentId}} - -grant_type=refresh_token&refresh_token=00895465d6994f72a9d926ceeed0f588 - -### 请求 /system/oauth2/token + DELETE 接口 => 成功 -DELETE {{baseUrl}}/system/oauth2/token?token=ca8a188f464441d6949c51493a2b7596 -Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw== -tenant-id: {{adminTenentId}} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.http b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.http new file mode 100644 index 0000000..f1a4946 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.http @@ -0,0 +1,49 @@ +### 请求 /system/oauth2/authorize + token 接口 => 成功 +POST {{baseUrl}}/system/oauth2/authorize +Content-Type: application/x-www-form-urlencoded +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +response_type=token&client_id=default&scope={"user_info": true}&redirect_uri=https://www.iocoder.cn&auto_approve=true + +### 请求 /system/oauth2/authorize + code 接口 => 成功 +POST {{baseUrl}}/system/oauth2/authorize +Content-Type: application/x-www-form-urlencoded +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +response_type=code&client_id=default&scope={"user_info": true}&redirect_uri=https://www.iocoder.cn&auto_approve=true + +### 请求 /system/oauth2/token + code 接口 => 成功 +POST {{baseUrl}}/system/oauth2/token +Content-Type: application/x-www-form-urlencoded +Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw== +tenant-id: {{adminTenentId}} + +grant_type=authorization_code&redirect_uri=https://www.iocoder.cn + +### 请求 /system/oauth2/token + password 接口 => 成功 +POST {{baseUrl}}/system/oauth2/token +Content-Type: application/x-www-form-urlencoded +Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw== +tenant-id: {{adminTenentId}} + +grant_type=password&username=admin&password=admin123&scope=user_info + +### 请求 /system/oauth2/token + refresh_token 接口 => 成功 +POST {{baseUrl}}/system/oauth2/token +Content-Type: application/x-www-form-urlencoded +Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw== +tenant-id: {{adminTenentId}} + +grant_type=refresh_token&refresh_token=00895465d6994f72a9d926ceeed0f588 + +### 请求 /system/oauth2/token + DELETE 接口 => 成功 +DELETE {{baseUrl}}/system/oauth2/token?token=ca8a188f464441d6949c51493a2b7596 +Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw== +tenant-id: {{adminTenentId}} + +### 请求 /system/oauth2/check-token 接口 => 成功 +POST {{baseUrl}}/system/oauth2/check-token?token=620d307c5b4148df8a98dd6c6c547106 +Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw== +tenant-id: {{adminTenentId}} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.java index 0edd0f8..6c510b4 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.java @@ -10,6 +10,7 @@ import cn.iocoder.yudao.framework.common.util.http.HttpUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAccessTokenRespVO; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenCheckTokenRespVO; import cn.iocoder.yudao.module.system.convert.oauth2.OAuth2OpenConvert; import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO; import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2ClientDO; @@ -17,6 +18,7 @@ import cn.iocoder.yudao.module.system.enums.auth.OAuth2GrantTypeEnum; import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ApproveService; import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ClientService; import cn.iocoder.yudao.module.system.service.oauth2.OAuth2GrantService; +import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService; import cn.iocoder.yudao.module.system.util.oauth2.OAuth2Utils; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; @@ -45,14 +47,14 @@ import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUti @Slf4j public class OAuth2OpenController { -// POST oauth/check_token CheckTokenEndpoint - @Resource private OAuth2GrantService oauth2GrantService; @Resource private OAuth2ClientService oauth2ClientService; @Resource private OAuth2ApproveService oauth2ApproveService; + @Resource + private OAuth2TokenService oauth2TokenService; /** * 对应 Spring Security OAuth 的 TokenEndpoint 类的 postAccessToken 方法 @@ -130,9 +132,6 @@ public class OAuth2OpenController { @RequestParam("token") String token) { // 校验客户端 String[] clientIdAndSecret = obtainBasicAuthorization(request); - if (ArrayUtil.isEmpty(clientIdAndSecret) || clientIdAndSecret.length != 2) { - throw exception0(BAD_REQUEST.getCode(), "client_id 或 client_secret 未正确传递"); - } OAuth2ClientDO client = oauth2ClientService.validOAuthClientFromCache(clientIdAndSecret[0], clientIdAndSecret[1], null, null, null); @@ -140,6 +139,26 @@ public class OAuth2OpenController { return success(oauth2GrantService.revokeToken(client.getClientId(), token)); } + /** + * 对应 Spring Security OAuth 的 CheckTokenEndpoint 类的 checkToken 方法 + */ + @PostMapping("/check-token") + @ApiOperation(value = "校验访问令牌") + @ApiImplicitParam(name = "token", required = true, value = "访问令牌", example = "biu", dataTypeClass = String.class) + @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 + public CommonResult checkToken(HttpServletRequest request, + @RequestParam("token") String token) { + // 校验客户端 + String[] clientIdAndSecret = obtainBasicAuthorization(request); + OAuth2ClientDO client = oauth2ClientService.validOAuthClientFromCache(clientIdAndSecret[0], clientIdAndSecret[1], + null, null, null); + + // 校验令牌 + OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.checkAccessToken(token); + Assert.notNull(accessTokenDO, "访问令牌不能为空"); // 防御性检查 + return success(OAuth2OpenConvert.INSTANCE.convert2(accessTokenDO)); + } + // GET oauth/authorize AuthorizationEndpoint TODO @GetMapping("/authorize") @ApiOperation(value = "获得授权信息", notes = "适合 code 授权码模式,或者 implicit 简化模式;在 authorize.vue 单点登录界面被【获取】调用") diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/open/OAuth2OpenAccessTokenRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/open/OAuth2OpenAccessTokenRespVO.java index cf9848a..4fdb4e5 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/open/OAuth2OpenAccessTokenRespVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/open/OAuth2OpenAccessTokenRespVO.java @@ -7,7 +7,7 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -@ApiModel("管理后台 - 访问令牌 Response VO") +@ApiModel("管理后台 - 【开放接口】访问令牌 Response VO") @Data @NoArgsConstructor @AllArgsConstructor diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/open/OAuth2OpenCheckTokenRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/open/OAuth2OpenCheckTokenRespVO.java new file mode 100644 index 0000000..b905e30 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/open/OAuth2OpenCheckTokenRespVO.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Set; + +@ApiModel("管理后台 - 【开放接口】校验令牌 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class OAuth2OpenCheckTokenRespVO { + + @ApiModelProperty(value = "用户编号", required = true, example = "666") + @JsonProperty("user_id") + private Long userId; + @ApiModelProperty(value = "用户类型", required = true, example = "2", notes = "参见 UserTypeEnum 枚举") + @JsonProperty("user_type") + private Integer userType; + @ApiModelProperty(value = "租户编号", required = true, example = "1024") + @JsonProperty("tenant_id") + private Long tenantId; + + @ApiModelProperty(value = "客户端编号", required = true, example = "car") + private String clientId; + @ApiModelProperty(value = "授权范围", required = true, example = "user_info") + private Set scopes; + + @ApiModelProperty(value = "访问令牌", required = true, example = "tudou") + @JsonProperty("access_token") + private String accessToken; + + @ApiModelProperty(value = "过期时间", required = true, example = "1593092157", notes = "时间戳 / 1000,即单位:秒") + @JsonProperty("exp") + private Long exp; +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/oauth2/OAuth2OpenConvert.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/oauth2/OAuth2OpenConvert.java index 61fbee1..cf0017d 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/oauth2/OAuth2OpenConvert.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/oauth2/OAuth2OpenConvert.java @@ -1,7 +1,9 @@ package cn.iocoder.yudao.module.system.convert.oauth2; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAccessTokenRespVO; +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenCheckTokenRespVO; import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO; import cn.iocoder.yudao.module.system.util.oauth2.OAuth2Utils; import org.mapstruct.Mapper; @@ -19,7 +21,14 @@ public interface OAuth2OpenConvert { respVO.setScope(OAuth2Utils.buildScopeStr(bean.getScopes())); return respVO; } - OAuth2OpenAccessTokenRespVO convert0(OAuth2AccessTokenDO bean); + default OAuth2OpenCheckTokenRespVO convert2(OAuth2AccessTokenDO bean) { + OAuth2OpenCheckTokenRespVO respVO = convert3(bean); + respVO.setExp(bean.getExpiresTime().getTime() / 1000L); + respVO.setUserType(UserTypeEnum.ADMIN.getValue()); + return respVO; + } + OAuth2OpenCheckTokenRespVO convert3(OAuth2AccessTokenDO bean); + } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/security/config/SecurityConfiguration.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/security/config/SecurityConfiguration.java index b43af78..c81809b 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/security/config/SecurityConfiguration.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/security/config/SecurityConfiguration.java @@ -37,7 +37,7 @@ public class SecurityConfiguration { registry.antMatchers(buildAdminApi("/system/sms/callback/**")).permitAll(); // OAuth2 API registry.antMatchers(buildAdminApi("/system/oauth2/token")).permitAll(); - registry.antMatchers(buildAdminApi("/system/oauth2/check_token")).permitAll(); + registry.antMatchers(buildAdminApi("/system/oauth2/check-token")).permitAll(); } }; -- libgit2 0.21.4