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 | 68 | return exchange.getBody(); |
| 69 | 69 | } |
| 70 | 70 | |
| 71 | + /** | |
| 72 | + * 校验访问令牌,并返回它的基本信息 | |
| 73 | + * | |
| 74 | + * @param token 访问令牌 | |
| 75 | + * @return 访问令牌的基本信息 | |
| 76 | + */ | |
| 71 | 77 | public CommonResult<OAuth2CheckTokenRespDTO> checkToken(String token) { |
| 72 | 78 | // 1.1 构建请求头 |
| 73 | 79 | HttpHeaders headers = new HttpHeaders(); |
| ... | ... | @@ -88,6 +94,33 @@ public class OAuth2Client { |
| 88 | 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 | 124 | private static void addClientHeader(HttpHeaders headers) { |
| 92 | 125 | // client 拼接,需要 BASE64 编码 |
| 93 | 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 | 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 | 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 | 77 | $(function () { |
| 51 | 78 | const accessToken = localStorage.getItem('ACCESS-TOKEN'); |
| 52 | 79 | // 情况一:未登录 |
| ... | ... | @@ -86,7 +113,7 @@ |
| 86 | 113 | <div id="yesLoginDiv" style="display: none"> |
| 87 | 114 | 您已登录!<button>退出登录</button> <br /> |
| 88 | 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 | 117 | </div> |
| 91 | 118 | </body> |
| 92 | 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 | 26 | private Long tenantId; |
| 27 | 27 | |
| 28 | 28 | @ApiModelProperty(value = "客户端编号", required = true, example = "car") |
| 29 | + @JsonProperty("client_id") | |
| 29 | 30 | private String clientId; |
| 30 | 31 | @ApiModelProperty(value = "授权范围", required = true, example = "user_info") |
| 31 | 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 | 17 | @ApiModelProperty(value = "用户编号", required = true, example = "1") |
| 18 | 18 | private Long id; |
| 19 | 19 | |
| 20 | - @ApiModelProperty(value = "用户昵称", required = true, example = "芋艿") | |
| 20 | + @ApiModelProperty(value = "用户账号", required = true, example = "芋艿") | |
| 21 | 21 | private String username; |
| 22 | 22 | |
| 23 | 23 | @ApiModelProperty(value = "用户昵称", required = true, example = "芋道") | ... | ... |
yudao-ui-admin/src/views/sso.vue
| ... | ... | @@ -19,7 +19,7 @@ |
| 19 | 19 | </el-tab-pane> |
| 20 | 20 | </el-tabs> |
| 21 | 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 | 25 | <el-form-item prop="scopes"> | ... | ... |