Commit 66034d26c06cbb7ad37e2e6579299260de9b728e

Authored by YunaiV
1 parent 6ca88277

完成 oauth2 code 授权码模式的实现

yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2Controller.http
1   -### 请求 /system/oauth2/authorize 接口 => 成功
  1 +### 请求 /system/oauth2/authorize + token 接口 => 成功
2 2 POST {{baseUrl}}/system/oauth2/authorize
3 3 Content-Type: application/x-www-form-urlencoded
4 4 Authorization: Bearer {{token}}
5 5 tenant-id: {{adminTenentId}}
6 6  
7 7 response_type=token&client_id=default&scope={"user_info": true}&redirect_uri=https://www.iocoder.cn&auto_approve=true
  8 +
  9 +### 请求 /system/oauth2/authorize + code 接口 => 成功
  10 +POST {{baseUrl}}/system/oauth2/authorize
  11 +Content-Type: application/x-www-form-urlencoded
  12 +Authorization: Bearer {{token}}
  13 +tenant-id: {{adminTenentId}}
  14 +
  15 +response_type=code&client_id=default&scope={"user_info": true}&redirect_uri=https://www.iocoder.cn&auto_approve=true
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2Controller.java
... ... @@ -49,7 +49,7 @@ public class OAuth2Controller {
49 49 // GET oauth/authorize AuthorizationEndpoint
50 50  
51 51 @Resource
52   - private OAuth2GrantService oAuth2GrantService;
  52 + private OAuth2GrantService oauth2GrantService;
53 53 @Resource
54 54 private OAuth2ClientService oauth2ClientService;
55 55 @Resource
... ... @@ -121,17 +121,18 @@ public class OAuth2Controller {
121 121 } else { // 2.2 假设 approved 非 null,说明是场景二
122 122 // 如果计算后不通过,则跳转一个错误链接
123 123 if (!oauth2ApproveService.updateAfterApproval(getLoginUserId(), getUserType(), clientId, scopes)) {
124   - return success("TODO");
  124 + return success(OAuth2Utils.buildUnsuccessfulRedirect(redirectUri, responseType, state,
  125 + "access_denied", "User denied access"));
125 126 }
126 127 }
127 128  
128 129 // 3.1 如果是 code 授权码模式,则发放 code 授权码,并重定向
129 130 List<String> approveScopes = convertList(scopes.entrySet(), Map.Entry::getKey, Map.Entry::getValue);
130 131 if (grantTypeEnum == OAuth2GrantTypeEnum.AUTHORIZATION_CODE) {
131   - return success(getAuthorizationCodeRedirect());
  132 + return success(getAuthorizationCodeRedirect(getLoginUserId(), client, approveScopes, redirectUri, state));
132 133 }
133 134 // 3.2 如果是 token 则是 implicit 简化模式,则发送 accessToken 访问令牌,并重定向
134   - return success(getImplicitGrantRedirect(getLoginUserId(), client, redirectUri, state, approveScopes));
  135 + return success(getImplicitGrantRedirect(getLoginUserId(), client, approveScopes, redirectUri, state));
135 136 }
136 137  
137 138 private static OAuth2GrantTypeEnum getGrantTypeEnum(String responseType) {
... ... @@ -145,17 +146,23 @@ public class OAuth2Controller {
145 146 }
146 147  
147 148 private String getImplicitGrantRedirect(Long userId, OAuth2ClientDO client,
148   - String redirectUri, String state, List<String> scopes) {
149   - OAuth2AccessTokenDO accessTokenDO = oAuth2GrantService.grantImplicit(userId, getUserType(), client.getClientId(), scopes);
  149 + List<String> scopes, String redirectUri, String state) {
  150 + // 1. 创建 access token 访问令牌
  151 + OAuth2AccessTokenDO accessTokenDO = oauth2GrantService.grantImplicit(userId, getUserType(), client.getClientId(), scopes);
150 152 Assert.notNull(accessTokenDO, "访问令牌不能为空"); // 防御性检查
151   - // 拼接 URL
  153 + // 2. 拼接重定向的 URL
152 154 // noinspection unchecked
153 155 return OAuth2Utils.buildImplicitRedirectUri(redirectUri, accessTokenDO.getAccessToken(), state, accessTokenDO.getExpiresTime(),
154 156 scopes, JsonUtils.parseObject(client.getAdditionalInformation(), Map.class));
155 157 }
156 158  
157   - private String getAuthorizationCodeRedirect() {
158   - return "";
  159 + private String getAuthorizationCodeRedirect(Long userId, OAuth2ClientDO client,
  160 + List<String> scopes, String redirectUri, String state) {
  161 + // 1. 创建 code 授权码
  162 + String authorizationCode = oauth2GrantService.grantAuthorizationCode(userId,getUserType(), client.getClientId(), scopes,
  163 + redirectUri, state);
  164 + // 2. 拼接重定向的 URL
  165 + return OAuth2Utils.buildAuthorizationCodeRedirectUri(redirectUri, authorizationCode, state);
159 166 }
160 167  
161 168 private Integer getUserType() {
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ApproveServiceImpl.java
... ... @@ -20,7 +20,7 @@ public class OAuth2ApproveServiceImpl implements OAuth2ApproveService {
20 20  
21 21 @Override
22 22 public boolean updateAfterApproval(Long userId, Integer userType, String clientId, Map<String, Boolean> scopes) {
23   - return true;
  23 + return false;
24 24 }
25 25  
26 26 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2GrantServiceImpl.java
... ... @@ -4,7 +4,6 @@ import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO;
4 4 import org.springframework.stereotype.Service;
5 5  
6 6 import javax.annotation.Resource;
7   -import java.util.Collection;
8 7 import java.util.List;
9 8  
10 9 /**
... ... @@ -28,7 +27,7 @@ public class OAuth2GrantServiceImpl implements OAuth2GrantService {
28 27 public String grantAuthorizationCode(Long userId, Integer userType,
29 28 String clientId, List<String> scopes,
30 29 String redirectUri, String state) {
31   - return null;
  30 + return "test";
32 31 }
33 32  
34 33 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/util/oauth2/OAuth2Utils.java
... ... @@ -14,6 +14,25 @@ import java.util.*;
14 14 public class OAuth2Utils {
15 15  
16 16 /**
  17 + * 构建授权码模式下,重定向的 URI
  18 + *
  19 + * copy from Spring Security OAuth2 的 AuthorizationEndpoint 类的 getSuccessfulRedirect 方法
  20 + *
  21 + * @param redirectUri 重定向 URI
  22 + * @param authorizationCode 授权码
  23 + * @param state 状态
  24 + * @return 授权码模式下的重定向 URI
  25 + */
  26 + public static String buildAuthorizationCodeRedirectUri(String redirectUri, String authorizationCode, String state) {
  27 + Map<String, String> query = new LinkedHashMap<>();
  28 + query.put("code", authorizationCode);
  29 + if (state != null) {
  30 + query.put("state", state);
  31 + }
  32 + return HttpUtils.append(redirectUri, query, null, false);
  33 + }
  34 +
  35 + /**
17 36 * 构建简化模式下,重定向的 URI
18 37 *
19 38 * copy from Spring Security OAuth2 的 AuthorizationEndpoint 类的 appendAccessToken 方法
... ... @@ -53,4 +72,15 @@ public class OAuth2Utils {
53 72 return HttpUtils.append(redirectUri, vars, keys, true);
54 73 }
55 74  
  75 + public static String buildUnsuccessfulRedirect(String redirectUri, String responseType, String state,
  76 + String error, String description) {
  77 + Map<String, String> query = new LinkedHashMap<String, String>();
  78 + query.put("error", error);
  79 + query.put("error_description", description);
  80 + if (state != null) {
  81 + query.put("state", state);
  82 + }
  83 + return HttpUtils.append(redirectUri, query, null, !responseType.contains("code"));
  84 + }
  85 +
56 86 }
... ...