Przeglądaj źródła

完成 yudao-sso-demo-by-code 退出登录

YunaiV 2 lat temu
rodzic
commit
ab40254bc1

+ 26 - 0
yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/client/OAuth2Client.java

@@ -121,6 +121,32 @@ public class OAuth2Client {
         return exchange.getBody();
     }
 
+    /**
+     * 删除访问令牌
+     *
+     * @param token 访问令牌
+     * @return 成功
+     */
+    public CommonResult<Boolean> revokeToken(String token) {
+        // 1.1 构建请求头
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
+        headers.set("tenant-id", TENANT_ID.toString());
+        addClientHeader(headers);
+        // 1.2 构建请求参数
+        MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
+        body.add("token", token);
+
+        // 2. 执行请求
+        ResponseEntity<CommonResult<Boolean>> exchange = restTemplate.exchange(
+                BASE_URL + "/token",
+                HttpMethod.DELETE,
+                new HttpEntity<>(body, headers),
+                new ParameterizedTypeReference<CommonResult<Boolean>>() {}); // 解决 CommonResult 的泛型丢失
+        Assert.isTrue(exchange.getStatusCode().is2xxSuccessful(), "响应必须是 200 成功");
+        return exchange.getBody();
+    }
+
     private static void addClientHeader(HttpHeaders headers) {
         // client 拼接,需要 BASE64 编码
         String client = CLIENT_ID + ":" + CLIENT_SECRET;

+ 19 - 0
yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/controller/AuthController.java

@@ -1,14 +1,17 @@
 package cn.iocoder.yudao.ssodemo.controller;
 
+import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.ssodemo.client.OAuth2Client;
 import cn.iocoder.yudao.ssodemo.client.dto.CommonResult;
 import cn.iocoder.yudao.ssodemo.client.dto.oauth2.OAuth2AccessTokenRespDTO;
+import cn.iocoder.yudao.ssodemo.framework.core.util.SecurityUtils;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
 
 @RestController
 @RequestMapping("/auth")
@@ -41,4 +44,20 @@ public class AuthController {
         return oauth2Client.refreshToken(refreshToken);
     }
 
+    /**
+     * 退出登录
+     *
+     * @param request 请求
+     * @return 成功
+     */
+    @PostMapping("/logout")
+    public CommonResult<Boolean> logout(HttpServletRequest request) {
+        String token = SecurityUtils.obtainAuthorization(request, "Authentication");
+        if (StrUtil.isNotBlank(token)) {
+            return oauth2Client.revokeToken(token);
+        }
+        // 返回成功
+        return new CommonResult<>();
+    }
+
 }

+ 2 - 0
yudao-example/yudao-sso-demo-by-code/src/main/java/cn/iocoder/yudao/ssodemo/framework/config/SecurityConfiguration.java

@@ -31,6 +31,8 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
                 .antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll()
                 // 2. 登录相关的接口,可匿名访问
                 .antMatchers("/auth/login-by-code").permitAll()
+                .antMatchers("/auth/refresh-token").permitAll()
+                .antMatchers("/auth/logout").permitAll()
                 // last. 兜底规则,必须认证
                 .and().authorizeRequests()
                 .anyRequest().authenticated();

+ 31 - 1
yudao-example/yudao-sso-demo-by-code/src/main/resources/static/index.html

@@ -74,6 +74,36 @@
       });
 		}
 
+    /**
+     * 刷新令牌
+     */
+    function logout() {
+      const accessToken = localStorage.getItem('ACCESS-TOKEN');
+      if (!accessToken) {
+        location.reload();
+        return;
+      }
+      $.ajax({
+        url: "http://127.0.0.1:18080/auth/logout",
+        method: 'POST',
+        headers: {
+          'Authentication': 'Bearer ' + accessToken
+        },
+        success: function (result) {
+          if (result.code !== 0) {
+            alert('退出登录失败,原因:' + result.msg)
+            return;
+          }
+          alert('退出登录成功!');
+          // 删除 localStorage 中
+          localStorage.removeItem('ACCESS-TOKEN');
+          localStorage.removeItem('REFRESH-TOKEN');
+
+          location.reload();
+        }
+      });
+    }
+
     $(function () {
       const accessToken = localStorage.getItem('ACCESS-TOKEN');
       // 情况一:未登录
@@ -111,7 +141,7 @@
 
 	<!-- 情况二:已登录:1)展示用户信息;2)刷新访问令牌;3)退出登录 -->
 	<div id="yesLoginDiv" style="display: none">
-		您已登录!<button>退出登录</button> <br />
+		您已登录!<button onclick="logout()">退出登录</button> <br />
 		昵称:<span id="nicknameSpan"> 加载中... </span> <button onclick="updateNickname()">修改昵称</button> <br />
 		访问令牌:<span id="accessTokenSpan"> 加载中... </span> <button onclick="refreshToken()">刷新令牌</button> <br />
 	</div>