From b14f06b8fae33419c746eb3766ecc81875e1d9f4 Mon Sep 17 00:00:00 2001 From: XinWei <2718030729@qq.com> Date: Wed, 17 Jul 2024 12:01:08 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8D=95=E7=82=B9=E7=99=BB=E5=BD=95cookie?= =?UTF-8?q?=E5=AD=98=E5=82=A8=E5=92=8C=E6=8B=A6=E6=88=AA=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + .../interceptor/PermissionInterceptor.java | 3 +- .../controller/interceptor/WebMvcConfig.java | 5 +- .../xxl/job/admin/core/util/CookieUtil.java | 2 +- .../xxl/job/admin/service/LoginService.java | 73 +++++++++++++++++-- .../src/main/resources/templates/login.ftl | 21 +++--- 6 files changed, 83 insertions(+), 22 deletions(-) diff --git a/.gitignore b/.gitignore index e55eb64b5..2dea96243 100644 --- a/.gitignore +++ b/.gitignore @@ -73,3 +73,4 @@ functions/mock screenshot .firebase sessionStore +/yudao-sso-demo-by-code/ diff --git a/ludu-job-admin/ludu-job-admin-biz/src/main/java/com/xxl/job/admin/controller/interceptor/PermissionInterceptor.java b/ludu-job-admin/ludu-job-admin-biz/src/main/java/com/xxl/job/admin/controller/interceptor/PermissionInterceptor.java index 840f0ebcf..94331b8c8 100644 --- a/ludu-job-admin/ludu-job-admin-biz/src/main/java/com/xxl/job/admin/controller/interceptor/PermissionInterceptor.java +++ b/ludu-job-admin/ludu-job-admin-biz/src/main/java/com/xxl/job/admin/controller/interceptor/PermissionInterceptor.java @@ -42,7 +42,8 @@ public class PermissionInterceptor implements AsyncHandlerInterceptor { if (needLogin) { XxlJobUser loginUser = loginService.ifLogin(request, response); - if (loginUser == null) { + Boolean authorState = loginService.ifAuthorizedLogin(request, response); + if (loginUser == null || !authorState) { response.setStatus(302); response.setHeader("location", request.getContextPath()+"/toLogin"); return false; diff --git a/ludu-job-admin/ludu-job-admin-biz/src/main/java/com/xxl/job/admin/controller/interceptor/WebMvcConfig.java b/ludu-job-admin/ludu-job-admin-biz/src/main/java/com/xxl/job/admin/controller/interceptor/WebMvcConfig.java index 0be6ba663..2030c729f 100644 --- a/ludu-job-admin/ludu-job-admin-biz/src/main/java/com/xxl/job/admin/controller/interceptor/WebMvcConfig.java +++ b/ludu-job-admin/ludu-job-admin-biz/src/main/java/com/xxl/job/admin/controller/interceptor/WebMvcConfig.java @@ -1,5 +1,6 @@ package com.xxl.job.admin.controller.interceptor; +import com.xxl.job.admin.enums.ApiConstants; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @@ -21,8 +22,8 @@ public class WebMvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { - registry.addInterceptor(permissionInterceptor).addPathPatterns("/**"); - registry.addInterceptor(cookieInterceptor).addPathPatterns("/**"); + registry.addInterceptor(permissionInterceptor).addPathPatterns("/**").excludePathPatterns("/auth/login-by-code", "/auth/refresh-token", "/auth/logout", ApiConstants.PREFIX + "/**"); + registry.addInterceptor(cookieInterceptor).addPathPatterns("/**").excludePathPatterns("/auth/login-by-code", "/auth/refresh-token", "/auth/logout", ApiConstants.PREFIX + "/**"); } } \ No newline at end of file diff --git a/ludu-job-admin/ludu-job-admin-biz/src/main/java/com/xxl/job/admin/core/util/CookieUtil.java b/ludu-job-admin/ludu-job-admin-biz/src/main/java/com/xxl/job/admin/core/util/CookieUtil.java index a1523aa47..870133f5f 100644 --- a/ludu-job-admin/ludu-job-admin-biz/src/main/java/com/xxl/job/admin/core/util/CookieUtil.java +++ b/ludu-job-admin/ludu-job-admin-biz/src/main/java/com/xxl/job/admin/core/util/CookieUtil.java @@ -37,7 +37,7 @@ public class CookieUtil { * @param value * @param maxAge */ - private static void set(HttpServletResponse response, String key, String value, String domain, String path, int maxAge, boolean isHttpOnly) { + public static void set(HttpServletResponse response, String key, String value, String domain, String path, int maxAge, boolean isHttpOnly) { Cookie cookie = new Cookie(key, value); if (domain != null) { cookie.setDomain(domain); diff --git a/ludu-job-admin/ludu-job-admin-biz/src/main/java/com/xxl/job/admin/service/LoginService.java b/ludu-job-admin/ludu-job-admin-biz/src/main/java/com/xxl/job/admin/service/LoginService.java index 319f85e8b..0b5b7cb0d 100644 --- a/ludu-job-admin/ludu-job-admin-biz/src/main/java/com/xxl/job/admin/service/LoginService.java +++ b/ludu-job-admin/ludu-job-admin-biz/src/main/java/com/xxl/job/admin/service/LoginService.java @@ -1,13 +1,23 @@ package com.xxl.job.admin.service; +import com.xxl.job.admin.client.OAuth2Client; +import com.xxl.job.admin.client.dto.CommonResult; +import com.xxl.job.admin.client.dto.oauth2.OAuth2AccessTokenRespDTO; +import com.xxl.job.admin.client.dto.oauth2.OAuth2CheckTokenRespDTO; import com.xxl.job.admin.core.model.XxlJobUser; import com.xxl.job.admin.core.util.CookieUtil; import com.xxl.job.admin.core.util.I18nUtil; import com.xxl.job.admin.core.util.JacksonUtil; import com.xxl.job.admin.dao.XxlJobUserDao; +import com.xxl.job.admin.framework.security.core.LoginUser; +import com.xxl.job.admin.framework.security.core.filter.TokenAuthenticationFilter; +import com.xxl.job.admin.framework.security.core.handler.AccessDeniedHandlerImpl; +import com.xxl.job.admin.framework.security.core.util.SecurityUtils; import com.xxl.job.core.biz.model.ReturnT; import org.springframework.context.annotation.Configuration; +import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.util.DigestUtils; +import org.springframework.util.StringUtils; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; @@ -21,17 +31,21 @@ import java.math.BigInteger; public class LoginService { public static final String LOGIN_IDENTITY_KEY = "XXL_JOB_LOGIN_IDENTITY"; - + public static final String ACCESS_TOKEN = "ACCESS_TOKEN"; + public static final String REFRESH_TOKEN = "REFRESH_TOKEN"; + @Resource + private OAuth2Client oauth2Client; @Resource private XxlJobUserDao xxlJobUserDao; - private String makeToken(XxlJobUser xxlJobUser){ + private String makeToken(XxlJobUser xxlJobUser) { String tokenJson = JacksonUtil.writeValueAsString(xxlJobUser); String tokenHex = new BigInteger(tokenJson.getBytes()).toString(16); return tokenHex; } - private XxlJobUser parseToken(String tokenHex){ + + private XxlJobUser parseToken(String tokenHex) { XxlJobUser xxlJobUser = null; if (tokenHex != null) { String tokenJson = new String(new BigInteger(tokenHex, 16).toByteArray()); // username_password(md5) @@ -41,10 +55,10 @@ public class LoginService { } - public ReturnT login(HttpServletRequest request, HttpServletResponse response, String username, String password, boolean ifRemember){ + public ReturnT login(HttpServletRequest request, HttpServletResponse response, String username, String password, boolean ifRemember) { // param - if (username==null || username.trim().length()==0 || password==null || password.trim().length()==0){ + if (username == null || username.trim().length() == 0 || password == null || password.trim().length() == 0) { return new ReturnT(500, I18nUtil.getString("login_param_empty")); } @@ -71,7 +85,7 @@ public class LoginService { * @param request * @param response */ - public ReturnT logout(HttpServletRequest request, HttpServletResponse response){ + public ReturnT logout(HttpServletRequest request, HttpServletResponse response) { CookieUtil.remove(request, response, LOGIN_IDENTITY_KEY); return ReturnT.SUCCESS; } @@ -82,7 +96,7 @@ public class LoginService { * @param request * @return */ - public XxlJobUser ifLogin(HttpServletRequest request, HttpServletResponse response){ + public XxlJobUser ifLogin(HttpServletRequest request, HttpServletResponse response) { // String cookieToken = CookieUtil.getValue(request, LOGIN_IDENTITY_KEY); // if (cookieToken != null) { @@ -112,4 +126,49 @@ public class LoginService { return test; } + /** + * 判断是否登录授权 + * + * @param request + * @param response + * @return java.lang.Boolean + */ + public Boolean ifAuthorizedLogin(HttpServletRequest request, HttpServletResponse response) { + String accessToken = CookieUtil.getValue(request, ACCESS_TOKEN); + String refreshToken = CookieUtil.getValue(request, REFRESH_TOKEN); + // 如果未登录授权过 + if (accessToken == null && refreshToken == null) { + // 登录授权 需要跳转登录授权页面 + // 基于 token 构建登录用户 + LoginUser loginUser = buildLoginUserByToken(accessToken); + // 设置当前用户 + if (loginUser != null) { + SecurityUtils.setLoginUser(loginUser, request); + } + return false; + } else if (accessToken == null) { + // 刷新令牌 不需要跳转登录授权页面 + OAuth2AccessTokenRespDTO refreshData = oauth2Client.refreshToken(refreshToken).getData(); + CookieUtil.set(response, ACCESS_TOKEN, refreshData.getAccessToken(), null, "/xxl-job-admin", refreshData.getExpiresIn().intValue(), true); + return true; + } + // 令牌未过期不需要重新登录 + return true; + } + private LoginUser buildLoginUserByToken(String token) { + try { + CommonResult accessTokenResult = oauth2Client.checkToken(token); + OAuth2CheckTokenRespDTO accessToken = accessTokenResult.getData(); + if (accessToken == null) { + return null; + } + // 构建登录用户 + return new LoginUser().setId(accessToken.getUserId()).setUserType(accessToken.getUserType()) + .setTenantId(accessToken.getTenantId()).setScopes(accessToken.getScopes()) + .setAccessToken(accessToken.getAccessToken()); + } catch (Exception exception) { + // 校验 Token 不通过时,考虑到一些接口是无需登录的,所以直接返回 null 即可 + return null; + } + } } diff --git a/ludu-job-admin/ludu-job-admin-biz/src/main/resources/templates/login.ftl b/ludu-job-admin/ludu-job-admin-biz/src/main/resources/templates/login.ftl index 671f7fb16..f88ef7124 100644 --- a/ludu-job-admin/ludu-job-admin-biz/src/main/resources/templates/login.ftl +++ b/ludu-job-admin/ludu-job-admin-biz/src/main/resources/templates/login.ftl @@ -54,7 +54,11 @@ + '&response_type=' + responseType; } - const accessToken = localStorage.getItem('ACCESS-TOKEN'); + // 读取 cookie + const accessToken = document.cookie + .replace(/(?:(?:^|.*;\s*)ACCESS_TOKEN\s*\=\s*([^;]*).*$)|^.*$/, "$1"); + const refreshToken = document.cookie + .replace(/(?:(?:^|.*;\s*)REFRESH_TOKEN\s*\=\s*([^;]*).*$)|^.*$/, "$1"); // 情况一:未登录 if (!accessToken) { // 获取 URL 中的查询参数 @@ -67,10 +71,10 @@ // 提交 const redirectUri = 'http://127.0.0.1:9090/xxl-job-admin/toLogin'; // 需要修改成,你回调的地址,就是在 index.html 拼接的 redirectUri $.ajax({ - url: "http://127.0.0.1:9090/xxl-job-admin/auth/login-by-code?code=" + code + url: "http://127.0.0.1:9090/xxl-job-admin/auth/login-by-code?code=" + code + '&redirectUri=' + redirectUri, method: 'POST', - success: function( result ) { + success: function (result) { if (result.code !== 0) { // layer.open({ // title: I18n.system_tips, @@ -81,20 +85,15 @@ alert('获得访问令牌失败,原因:' + result.msg) return; } - // 设置到 localStorage 中 - localStorage.setItem('ACCESS-TOKEN', result.data.access_token); - localStorage.setItem('REFRESH-TOKEN', result.data.refresh_token); - localStorage.setItem('EXPIRES-IN', Date.now() + result.data.expires_in * 1000); + // 设置cookie + document.cookie = "ACCESS_TOKEN=" + result.data.access_token + "; max-age=" + result.data.expires_in + "; path=/xxl-job-admin"; + document.cookie = "REFRESH_TOKEN=" + result.data.refresh_token + "; max-age=43000; path=/xxl-job-admin"; // 跳转回首页 window.location.href = '/xxl-job-admin'; } }) } } - // 情况二:Token失效(暂未实现) - else if (Date.now() > localStorage.getItem('EXPIRES-IN')) { - console.log('重新获取授权码') - } // 情况三:已登录 else { window.location.href = '/xxl-job-admin';