Commit ff54f169079ceb5b77d93cc60f5d2a167c6c253e
1 parent
ea71002e
完成 yudao-sso-demo-by-code 刷新访问令牌
Showing
6 changed files
with
75 additions
and
3 deletions
yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/OAuth2Client.java
| @@ -68,6 +68,12 @@ public class OAuth2Client { | @@ -68,6 +68,12 @@ public class OAuth2Client { | ||
| 68 | return exchange.getBody(); | 68 | return exchange.getBody(); |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | + /** | ||
| 72 | + * 校验访问令牌,并返回它的基本信息 | ||
| 73 | + * | ||
| 74 | + * @param token 访问令牌 | ||
| 75 | + * @return 访问令牌的基本信息 | ||
| 76 | + */ | ||
| 71 | public CommonResult<OAuth2CheckTokenRespDTO> checkToken(String token) { | 77 | public CommonResult<OAuth2CheckTokenRespDTO> checkToken(String token) { |
| 72 | // 1.1 构建请求头 | 78 | // 1.1 构建请求头 |
| 73 | HttpHeaders headers = new HttpHeaders(); | 79 | HttpHeaders headers = new HttpHeaders(); |
| @@ -88,6 +94,33 @@ public class OAuth2Client { | @@ -88,6 +94,33 @@ public class OAuth2Client { | ||
| 88 | return exchange.getBody(); | 94 | return exchange.getBody(); |
| 89 | } | 95 | } |
| 90 | 96 | ||
| 97 | + /** | ||
| 98 | + * 使用刷新令牌,获得(刷新)访问令牌 | ||
| 99 | + * | ||
| 100 | + * @param refreshToken 刷新令牌 | ||
| 101 | + * @return 访问令牌 | ||
| 102 | + */ | ||
| 103 | + public CommonResult<OAuth2AccessTokenRespDTO> refreshToken(String refreshToken) { | ||
| 104 | + // 1.1 构建请求头 | ||
| 105 | + HttpHeaders headers = new HttpHeaders(); | ||
| 106 | + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); | ||
| 107 | + headers.set("tenant-id", TENANT_ID.toString()); | ||
| 108 | + addClientHeader(headers); | ||
| 109 | + // 1.2 构建请求参数 | ||
| 110 | + MultiValueMap<String, Object> body = new LinkedMultiValueMap<>(); | ||
| 111 | + body.add("grant_type", "refresh_token"); | ||
| 112 | + body.add("refresh_token", refreshToken); | ||
| 113 | + | ||
| 114 | + // 2. 执行请求 | ||
| 115 | + ResponseEntity<CommonResult<OAuth2AccessTokenRespDTO>> exchange = restTemplate.exchange( | ||
| 116 | + BASE_URL + "/token", | ||
| 117 | + HttpMethod.POST, | ||
| 118 | + new HttpEntity<>(body, headers), | ||
| 119 | + new ParameterizedTypeReference<CommonResult<OAuth2AccessTokenRespDTO>>() {}); // 解决 CommonResult 的泛型丢失 | ||
| 120 | + Assert.isTrue(exchange.getStatusCode().is2xxSuccessful(), "响应必须是 200 成功"); | ||
| 121 | + return exchange.getBody(); | ||
| 122 | + } | ||
| 123 | + | ||
| 91 | private static void addClientHeader(HttpHeaders headers) { | 124 | private static void addClientHeader(HttpHeaders headers) { |
| 92 | // client 拼接,需要 BASE64 编码 | 125 | // client 拼接,需要 BASE64 编码 |
| 93 | String client = CLIENT_ID + ":" + CLIENT_SECRET; | 126 | String client = CLIENT_ID + ":" + CLIENT_SECRET; |
yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/controller/AuthController.java
| @@ -30,4 +30,15 @@ public class AuthController { | @@ -30,4 +30,15 @@ public class AuthController { | ||
| 30 | return oauth2Client.postAccessToken(code, redirectUri); | 30 | return oauth2Client.postAccessToken(code, redirectUri); |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | + /** | ||
| 34 | + * 使用刷新令牌,获得(刷新)访问令牌 | ||
| 35 | + * | ||
| 36 | + * @param refreshToken 刷新令牌 | ||
| 37 | + * @return 访问令牌;注意,实际项目中,最好创建对应的 ResponseVO 类,只返回必要的字段 | ||
| 38 | + */ | ||
| 39 | + @PostMapping("/refresh-token") | ||
| 40 | + public CommonResult<OAuth2AccessTokenRespDTO> refreshToken(@RequestParam("refreshToken") String refreshToken) { | ||
| 41 | + return oauth2Client.refreshToken(refreshToken); | ||
| 42 | + } | ||
| 43 | + | ||
| 33 | } | 44 | } |
yudao-example/yudao-sso-demo-by-code/src/main/resources/static/index.html
| @@ -47,6 +47,33 @@ | @@ -47,6 +47,33 @@ | ||
| 47 | }); | 47 | }); |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | + /** | ||
| 51 | + * 刷新令牌 | ||
| 52 | + */ | ||
| 53 | + function refreshToken() { | ||
| 54 | + const refreshToken = localStorage.getItem('REFRESH-TOKEN'); | ||
| 55 | + if (!refreshToken) { | ||
| 56 | + alert("获取不到刷新令牌"); | ||
| 57 | + return; | ||
| 58 | + } | ||
| 59 | + $.ajax({ | ||
| 60 | + url: "http://127.0.0.1:18080/auth/refresh-token?refreshToken=" + refreshToken, | ||
| 61 | + method: 'POST', | ||
| 62 | + success: function (result) { | ||
| 63 | + if (result.code !== 0) { | ||
| 64 | + alert('刷新访问令牌失败,原因:' + result.msg) | ||
| 65 | + return; | ||
| 66 | + } | ||
| 67 | + alert('更新访问令牌成功!'); | ||
| 68 | + $('#accessTokenSpan').html(result.data.access_token); | ||
| 69 | + | ||
| 70 | + // 设置到 localStorage 中 | ||
| 71 | + localStorage.setItem('ACCESS-TOKEN', result.data.access_token); | ||
| 72 | + localStorage.setItem('REFRESH-TOKEN', result.data.refresh_token); | ||
| 73 | + } | ||
| 74 | + }); | ||
| 75 | + } | ||
| 76 | + | ||
| 50 | $(function () { | 77 | $(function () { |
| 51 | const accessToken = localStorage.getItem('ACCESS-TOKEN'); | 78 | const accessToken = localStorage.getItem('ACCESS-TOKEN'); |
| 52 | // 情况一:未登录 | 79 | // 情况一:未登录 |
| @@ -86,7 +113,7 @@ | @@ -86,7 +113,7 @@ | ||
| 86 | <div id="yesLoginDiv" style="display: none"> | 113 | <div id="yesLoginDiv" style="display: none"> |
| 87 | 您已登录!<button>退出登录</button> <br /> | 114 | 您已登录!<button>退出登录</button> <br /> |
| 88 | 昵称:<span id="nicknameSpan"> 加载中... </span> <button onclick="updateNickname()">修改昵称</button> <br /> | 115 | 昵称:<span id="nicknameSpan"> 加载中... </span> <button onclick="updateNickname()">修改昵称</button> <br /> |
| 89 | - 访问令牌:<span id="accessTokenSpan"> 加载中... </span> <br /> | 116 | + 访问令牌:<span id="accessTokenSpan"> 加载中... </span> <button onclick="refreshToken()">刷新令牌</button> <br /> |
| 90 | </div> | 117 | </div> |
| 91 | </body> | 118 | </body> |
| 92 | <style> | 119 | <style> |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/open/OAuth2OpenCheckTokenRespVO.java
| @@ -26,6 +26,7 @@ public class OAuth2OpenCheckTokenRespVO { | @@ -26,6 +26,7 @@ public class OAuth2OpenCheckTokenRespVO { | ||
| 26 | private Long tenantId; | 26 | private Long tenantId; |
| 27 | 27 | ||
| 28 | @ApiModelProperty(value = "客户端编号", required = true, example = "car") | 28 | @ApiModelProperty(value = "客户端编号", required = true, example = "car") |
| 29 | + @JsonProperty("client_id") | ||
| 29 | private String clientId; | 30 | private String clientId; |
| 30 | @ApiModelProperty(value = "授权范围", required = true, example = "user_info") | 31 | @ApiModelProperty(value = "授权范围", required = true, example = "user_info") |
| 31 | private List<String> scopes; | 32 | private List<String> scopes; |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/user/OAuth2UserInfoRespVO.java
| @@ -17,7 +17,7 @@ public class OAuth2UserInfoRespVO { | @@ -17,7 +17,7 @@ public class OAuth2UserInfoRespVO { | ||
| 17 | @ApiModelProperty(value = "用户编号", required = true, example = "1") | 17 | @ApiModelProperty(value = "用户编号", required = true, example = "1") |
| 18 | private Long id; | 18 | private Long id; |
| 19 | 19 | ||
| 20 | - @ApiModelProperty(value = "用户昵称", required = true, example = "芋艿") | 20 | + @ApiModelProperty(value = "用户账号", required = true, example = "芋艿") |
| 21 | private String username; | 21 | private String username; |
| 22 | 22 | ||
| 23 | @ApiModelProperty(value = "用户昵称", required = true, example = "芋道") | 23 | @ApiModelProperty(value = "用户昵称", required = true, example = "芋道") |
yudao-ui-admin/src/views/sso.vue
| @@ -19,7 +19,7 @@ | @@ -19,7 +19,7 @@ | ||
| 19 | </el-tab-pane> | 19 | </el-tab-pane> |
| 20 | </el-tabs> | 20 | </el-tabs> |
| 21 | <div> | 21 | <div> |
| 22 | - <el-form ref="loginForm" :model="loginForm" :rules="LoginRules" class="login-form"> | 22 | + <el-form ref="loginForm" :model="loginForm" class="login-form"> |
| 23 | <!-- 授权范围的选择 --> | 23 | <!-- 授权范围的选择 --> |
| 24 | 此第三方应用请求获得以下权限: | 24 | 此第三方应用请求获得以下权限: |
| 25 | <el-form-item prop="scopes"> | 25 | <el-form-item prop="scopes"> |