Commit 65ee56c81194209d827a592a9224c3c2b7ec3a2b
1 parent
0900b9e1
完成 oauth2 check-token 校验 token 的实现
Showing
6 changed files
with
81 additions
and
8 deletions
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2Controller.http renamed to yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.http
| @@ -42,3 +42,8 @@ grant_type=refresh_token&refresh_token=00895465d6994f72a9d926ceeed0f588 | @@ -42,3 +42,8 @@ grant_type=refresh_token&refresh_token=00895465d6994f72a9d926ceeed0f588 | ||
| 42 | DELETE {{baseUrl}}/system/oauth2/token?token=ca8a188f464441d6949c51493a2b7596 | 42 | DELETE {{baseUrl}}/system/oauth2/token?token=ca8a188f464441d6949c51493a2b7596 |
| 43 | Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw== | 43 | Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw== |
| 44 | tenant-id: {{adminTenentId}} | 44 | tenant-id: {{adminTenentId}} |
| 45 | + | ||
| 46 | +### 请求 /system/oauth2/check-token 接口 => 成功 | ||
| 47 | +POST {{baseUrl}}/system/oauth2/check-token?token=620d307c5b4148df8a98dd6c6c547106 | ||
| 48 | +Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw== | ||
| 49 | +tenant-id: {{adminTenentId}} |
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; | @@ -10,6 +10,7 @@ import cn.iocoder.yudao.framework.common.util.http.HttpUtils; | ||
| 10 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | 10 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; |
| 11 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; | 11 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; |
| 12 | import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAccessTokenRespVO; | 12 | import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAccessTokenRespVO; |
| 13 | +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenCheckTokenRespVO; | ||
| 13 | import cn.iocoder.yudao.module.system.convert.oauth2.OAuth2OpenConvert; | 14 | import cn.iocoder.yudao.module.system.convert.oauth2.OAuth2OpenConvert; |
| 14 | import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO; | 15 | import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO; |
| 15 | import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2ClientDO; | 16 | import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2ClientDO; |
| @@ -17,6 +18,7 @@ import cn.iocoder.yudao.module.system.enums.auth.OAuth2GrantTypeEnum; | @@ -17,6 +18,7 @@ import cn.iocoder.yudao.module.system.enums.auth.OAuth2GrantTypeEnum; | ||
| 17 | import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ApproveService; | 18 | import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ApproveService; |
| 18 | import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ClientService; | 19 | import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ClientService; |
| 19 | import cn.iocoder.yudao.module.system.service.oauth2.OAuth2GrantService; | 20 | import cn.iocoder.yudao.module.system.service.oauth2.OAuth2GrantService; |
| 21 | +import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService; | ||
| 20 | import cn.iocoder.yudao.module.system.util.oauth2.OAuth2Utils; | 22 | import cn.iocoder.yudao.module.system.util.oauth2.OAuth2Utils; |
| 21 | import io.swagger.annotations.Api; | 23 | import io.swagger.annotations.Api; |
| 22 | import io.swagger.annotations.ApiImplicitParam; | 24 | import io.swagger.annotations.ApiImplicitParam; |
| @@ -45,14 +47,14 @@ import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUti | @@ -45,14 +47,14 @@ import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUti | ||
| 45 | @Slf4j | 47 | @Slf4j |
| 46 | public class OAuth2OpenController { | 48 | public class OAuth2OpenController { |
| 47 | 49 | ||
| 48 | -// POST oauth/check_token CheckTokenEndpoint | ||
| 49 | - | ||
| 50 | @Resource | 50 | @Resource |
| 51 | private OAuth2GrantService oauth2GrantService; | 51 | private OAuth2GrantService oauth2GrantService; |
| 52 | @Resource | 52 | @Resource |
| 53 | private OAuth2ClientService oauth2ClientService; | 53 | private OAuth2ClientService oauth2ClientService; |
| 54 | @Resource | 54 | @Resource |
| 55 | private OAuth2ApproveService oauth2ApproveService; | 55 | private OAuth2ApproveService oauth2ApproveService; |
| 56 | + @Resource | ||
| 57 | + private OAuth2TokenService oauth2TokenService; | ||
| 56 | 58 | ||
| 57 | /** | 59 | /** |
| 58 | * 对应 Spring Security OAuth 的 TokenEndpoint 类的 postAccessToken 方法 | 60 | * 对应 Spring Security OAuth 的 TokenEndpoint 类的 postAccessToken 方法 |
| @@ -130,9 +132,6 @@ public class OAuth2OpenController { | @@ -130,9 +132,6 @@ public class OAuth2OpenController { | ||
| 130 | @RequestParam("token") String token) { | 132 | @RequestParam("token") String token) { |
| 131 | // 校验客户端 | 133 | // 校验客户端 |
| 132 | String[] clientIdAndSecret = obtainBasicAuthorization(request); | 134 | String[] clientIdAndSecret = obtainBasicAuthorization(request); |
| 133 | - if (ArrayUtil.isEmpty(clientIdAndSecret) || clientIdAndSecret.length != 2) { | ||
| 134 | - throw exception0(BAD_REQUEST.getCode(), "client_id 或 client_secret 未正确传递"); | ||
| 135 | - } | ||
| 136 | OAuth2ClientDO client = oauth2ClientService.validOAuthClientFromCache(clientIdAndSecret[0], clientIdAndSecret[1], | 135 | OAuth2ClientDO client = oauth2ClientService.validOAuthClientFromCache(clientIdAndSecret[0], clientIdAndSecret[1], |
| 137 | null, null, null); | 136 | null, null, null); |
| 138 | 137 | ||
| @@ -140,6 +139,26 @@ public class OAuth2OpenController { | @@ -140,6 +139,26 @@ public class OAuth2OpenController { | ||
| 140 | return success(oauth2GrantService.revokeToken(client.getClientId(), token)); | 139 | return success(oauth2GrantService.revokeToken(client.getClientId(), token)); |
| 141 | } | 140 | } |
| 142 | 141 | ||
| 142 | + /** | ||
| 143 | + * 对应 Spring Security OAuth 的 CheckTokenEndpoint 类的 checkToken 方法 | ||
| 144 | + */ | ||
| 145 | + @PostMapping("/check-token") | ||
| 146 | + @ApiOperation(value = "校验访问令牌") | ||
| 147 | + @ApiImplicitParam(name = "token", required = true, value = "访问令牌", example = "biu", dataTypeClass = String.class) | ||
| 148 | + @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 | ||
| 149 | + public CommonResult<OAuth2OpenCheckTokenRespVO> checkToken(HttpServletRequest request, | ||
| 150 | + @RequestParam("token") String token) { | ||
| 151 | + // 校验客户端 | ||
| 152 | + String[] clientIdAndSecret = obtainBasicAuthorization(request); | ||
| 153 | + OAuth2ClientDO client = oauth2ClientService.validOAuthClientFromCache(clientIdAndSecret[0], clientIdAndSecret[1], | ||
| 154 | + null, null, null); | ||
| 155 | + | ||
| 156 | + // 校验令牌 | ||
| 157 | + OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.checkAccessToken(token); | ||
| 158 | + Assert.notNull(accessTokenDO, "访问令牌不能为空"); // 防御性检查 | ||
| 159 | + return success(OAuth2OpenConvert.INSTANCE.convert2(accessTokenDO)); | ||
| 160 | + } | ||
| 161 | + | ||
| 143 | // GET oauth/authorize AuthorizationEndpoint TODO | 162 | // GET oauth/authorize AuthorizationEndpoint TODO |
| 144 | @GetMapping("/authorize") | 163 | @GetMapping("/authorize") |
| 145 | @ApiOperation(value = "获得授权信息", notes = "适合 code 授权码模式,或者 implicit 简化模式;在 authorize.vue 单点登录界面被【获取】调用") | 164 | @ApiOperation(value = "获得授权信息", notes = "适合 code 授权码模式,或者 implicit 简化模式;在 authorize.vue 单点登录界面被【获取】调用") |
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; | @@ -7,7 +7,7 @@ import lombok.AllArgsConstructor; | ||
| 7 | import lombok.Data; | 7 | import lombok.Data; |
| 8 | import lombok.NoArgsConstructor; | 8 | import lombok.NoArgsConstructor; |
| 9 | 9 | ||
| 10 | -@ApiModel("管理后台 - 访问令牌 Response VO") | 10 | +@ApiModel("管理后台 - 【开放接口】访问令牌 Response VO") |
| 11 | @Data | 11 | @Data |
| 12 | @NoArgsConstructor | 12 | @NoArgsConstructor |
| 13 | @AllArgsConstructor | 13 | @AllArgsConstructor |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/open/OAuth2OpenCheckTokenRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open; | ||
| 2 | + | ||
| 3 | +import com.fasterxml.jackson.annotation.JsonProperty; | ||
| 4 | +import io.swagger.annotations.ApiModel; | ||
| 5 | +import io.swagger.annotations.ApiModelProperty; | ||
| 6 | +import lombok.AllArgsConstructor; | ||
| 7 | +import lombok.Data; | ||
| 8 | +import lombok.NoArgsConstructor; | ||
| 9 | + | ||
| 10 | +import java.util.Set; | ||
| 11 | + | ||
| 12 | +@ApiModel("管理后台 - 【开放接口】校验令牌 Response VO") | ||
| 13 | +@Data | ||
| 14 | +@NoArgsConstructor | ||
| 15 | +@AllArgsConstructor | ||
| 16 | +public class OAuth2OpenCheckTokenRespVO { | ||
| 17 | + | ||
| 18 | + @ApiModelProperty(value = "用户编号", required = true, example = "666") | ||
| 19 | + @JsonProperty("user_id") | ||
| 20 | + private Long userId; | ||
| 21 | + @ApiModelProperty(value = "用户类型", required = true, example = "2", notes = "参见 UserTypeEnum 枚举") | ||
| 22 | + @JsonProperty("user_type") | ||
| 23 | + private Integer userType; | ||
| 24 | + @ApiModelProperty(value = "租户编号", required = true, example = "1024") | ||
| 25 | + @JsonProperty("tenant_id") | ||
| 26 | + private Long tenantId; | ||
| 27 | + | ||
| 28 | + @ApiModelProperty(value = "客户端编号", required = true, example = "car") | ||
| 29 | + private String clientId; | ||
| 30 | + @ApiModelProperty(value = "授权范围", required = true, example = "user_info") | ||
| 31 | + private Set<String> scopes; | ||
| 32 | + | ||
| 33 | + @ApiModelProperty(value = "访问令牌", required = true, example = "tudou") | ||
| 34 | + @JsonProperty("access_token") | ||
| 35 | + private String accessToken; | ||
| 36 | + | ||
| 37 | + @ApiModelProperty(value = "过期时间", required = true, example = "1593092157", notes = "时间戳 / 1000,即单位:秒") | ||
| 38 | + @JsonProperty("exp") | ||
| 39 | + private Long exp; | ||
| 40 | +} |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/oauth2/OAuth2OpenConvert.java
| 1 | package cn.iocoder.yudao.module.system.convert.oauth2; | 1 | package cn.iocoder.yudao.module.system.convert.oauth2; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; | ||
| 3 | import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; | 4 | import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; |
| 4 | import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAccessTokenRespVO; | 5 | import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAccessTokenRespVO; |
| 6 | +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenCheckTokenRespVO; | ||
| 5 | import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO; | 7 | import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO; |
| 6 | import cn.iocoder.yudao.module.system.util.oauth2.OAuth2Utils; | 8 | import cn.iocoder.yudao.module.system.util.oauth2.OAuth2Utils; |
| 7 | import org.mapstruct.Mapper; | 9 | import org.mapstruct.Mapper; |
| @@ -19,7 +21,14 @@ public interface OAuth2OpenConvert { | @@ -19,7 +21,14 @@ public interface OAuth2OpenConvert { | ||
| 19 | respVO.setScope(OAuth2Utils.buildScopeStr(bean.getScopes())); | 21 | respVO.setScope(OAuth2Utils.buildScopeStr(bean.getScopes())); |
| 20 | return respVO; | 22 | return respVO; |
| 21 | } | 23 | } |
| 22 | - | ||
| 23 | OAuth2OpenAccessTokenRespVO convert0(OAuth2AccessTokenDO bean); | 24 | OAuth2OpenAccessTokenRespVO convert0(OAuth2AccessTokenDO bean); |
| 24 | 25 | ||
| 26 | + default OAuth2OpenCheckTokenRespVO convert2(OAuth2AccessTokenDO bean) { | ||
| 27 | + OAuth2OpenCheckTokenRespVO respVO = convert3(bean); | ||
| 28 | + respVO.setExp(bean.getExpiresTime().getTime() / 1000L); | ||
| 29 | + respVO.setUserType(UserTypeEnum.ADMIN.getValue()); | ||
| 30 | + return respVO; | ||
| 31 | + } | ||
| 32 | + OAuth2OpenCheckTokenRespVO convert3(OAuth2AccessTokenDO bean); | ||
| 33 | + | ||
| 25 | } | 34 | } |
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 { | @@ -37,7 +37,7 @@ public class SecurityConfiguration { | ||
| 37 | registry.antMatchers(buildAdminApi("/system/sms/callback/**")).permitAll(); | 37 | registry.antMatchers(buildAdminApi("/system/sms/callback/**")).permitAll(); |
| 38 | // OAuth2 API | 38 | // OAuth2 API |
| 39 | registry.antMatchers(buildAdminApi("/system/oauth2/token")).permitAll(); | 39 | registry.antMatchers(buildAdminApi("/system/oauth2/token")).permitAll(); |
| 40 | - registry.antMatchers(buildAdminApi("/system/oauth2/check_token")).permitAll(); | 40 | + registry.antMatchers(buildAdminApi("/system/oauth2/check-token")).permitAll(); |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | }; | 43 | }; |