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 POST {{baseUrl}}/system/oauth2/authorize 2 POST {{baseUrl}}/system/oauth2/authorize
3 Content-Type: application/x-www-form-urlencoded 3 Content-Type: application/x-www-form-urlencoded
4 Authorization: Bearer {{token}} 4 Authorization: Bearer {{token}}
5 tenant-id: {{adminTenentId}} 5 tenant-id: {{adminTenentId}}
6 6
7 response_type=token&client_id=default&scope={"user_info": true}&redirect_uri=https://www.iocoder.cn&auto_approve=true 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,7 +49,7 @@ public class OAuth2Controller {
49 // GET oauth/authorize AuthorizationEndpoint 49 // GET oauth/authorize AuthorizationEndpoint
50 50
51 @Resource 51 @Resource
52 - private OAuth2GrantService oAuth2GrantService; 52 + private OAuth2GrantService oauth2GrantService;
53 @Resource 53 @Resource
54 private OAuth2ClientService oauth2ClientService; 54 private OAuth2ClientService oauth2ClientService;
55 @Resource 55 @Resource
@@ -121,17 +121,18 @@ public class OAuth2Controller { @@ -121,17 +121,18 @@ public class OAuth2Controller {
121 } else { // 2.2 假设 approved 非 null,说明是场景二 121 } else { // 2.2 假设 approved 非 null,说明是场景二
122 // 如果计算后不通过,则跳转一个错误链接 122 // 如果计算后不通过,则跳转一个错误链接
123 if (!oauth2ApproveService.updateAfterApproval(getLoginUserId(), getUserType(), clientId, scopes)) { 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 // 3.1 如果是 code 授权码模式,则发放 code 授权码,并重定向 129 // 3.1 如果是 code 授权码模式,则发放 code 授权码,并重定向
129 List<String> approveScopes = convertList(scopes.entrySet(), Map.Entry::getKey, Map.Entry::getValue); 130 List<String> approveScopes = convertList(scopes.entrySet(), Map.Entry::getKey, Map.Entry::getValue);
130 if (grantTypeEnum == OAuth2GrantTypeEnum.AUTHORIZATION_CODE) { 131 if (grantTypeEnum == OAuth2GrantTypeEnum.AUTHORIZATION_CODE) {
131 - return success(getAuthorizationCodeRedirect()); 132 + return success(getAuthorizationCodeRedirect(getLoginUserId(), client, approveScopes, redirectUri, state));
132 } 133 }
133 // 3.2 如果是 token 则是 implicit 简化模式,则发送 accessToken 访问令牌,并重定向 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 private static OAuth2GrantTypeEnum getGrantTypeEnum(String responseType) { 138 private static OAuth2GrantTypeEnum getGrantTypeEnum(String responseType) {
@@ -145,17 +146,23 @@ public class OAuth2Controller { @@ -145,17 +146,23 @@ public class OAuth2Controller {
145 } 146 }
146 147
147 private String getImplicitGrantRedirect(Long userId, OAuth2ClientDO client, 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 Assert.notNull(accessTokenDO, "访问令牌不能为空"); // 防御性检查 152 Assert.notNull(accessTokenDO, "访问令牌不能为空"); // 防御性检查
151 - // 拼接 URL 153 + // 2. 拼接重定向的 URL
152 // noinspection unchecked 154 // noinspection unchecked
153 return OAuth2Utils.buildImplicitRedirectUri(redirectUri, accessTokenDO.getAccessToken(), state, accessTokenDO.getExpiresTime(), 155 return OAuth2Utils.buildImplicitRedirectUri(redirectUri, accessTokenDO.getAccessToken(), state, accessTokenDO.getExpiresTime(),
154 scopes, JsonUtils.parseObject(client.getAdditionalInformation(), Map.class)); 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 private Integer getUserType() { 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,7 +20,7 @@ public class OAuth2ApproveServiceImpl implements OAuth2ApproveService {
20 20
21 @Override 21 @Override
22 public boolean updateAfterApproval(Long userId, Integer userType, String clientId, Map<String, Boolean> scopes) { 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,7 +4,6 @@ import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO;
4 import org.springframework.stereotype.Service; 4 import org.springframework.stereotype.Service;
5 5
6 import javax.annotation.Resource; 6 import javax.annotation.Resource;
7 -import java.util.Collection;  
8 import java.util.List; 7 import java.util.List;
9 8
10 /** 9 /**
@@ -28,7 +27,7 @@ public class OAuth2GrantServiceImpl implements OAuth2GrantService { @@ -28,7 +27,7 @@ public class OAuth2GrantServiceImpl implements OAuth2GrantService {
28 public String grantAuthorizationCode(Long userId, Integer userType, 27 public String grantAuthorizationCode(Long userId, Integer userType,
29 String clientId, List<String> scopes, 28 String clientId, List<String> scopes,
30 String redirectUri, String state) { 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,6 +14,25 @@ import java.util.*;
14 public class OAuth2Utils { 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 * 构建简化模式下,重定向的 URI 36 * 构建简化模式下,重定向的 URI
18 * 37 *
19 * copy from Spring Security OAuth2 的 AuthorizationEndpoint 类的 appendAccessToken 方法 38 * copy from Spring Security OAuth2 的 AuthorizationEndpoint 类的 appendAccessToken 方法
@@ -53,4 +72,15 @@ public class OAuth2Utils { @@ -53,4 +72,15 @@ public class OAuth2Utils {
53 return HttpUtils.append(redirectUri, vars, keys, true); 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 }