单点登录cookie存储和拦截判断

This commit is contained in:
XinWei 2024-07-17 12:01:08 +08:00
parent e9bca69a3a
commit b14f06b8fa
6 changed files with 83 additions and 22 deletions

1
.gitignore vendored
View File

@ -73,3 +73,4 @@ functions/mock
screenshot screenshot
.firebase .firebase
sessionStore sessionStore
/yudao-sso-demo-by-code/

View File

@ -42,7 +42,8 @@ public class PermissionInterceptor implements AsyncHandlerInterceptor {
if (needLogin) { if (needLogin) {
XxlJobUser loginUser = loginService.ifLogin(request, response); XxlJobUser loginUser = loginService.ifLogin(request, response);
if (loginUser == null) { Boolean authorState = loginService.ifAuthorizedLogin(request, response);
if (loginUser == null || !authorState) {
response.setStatus(302); response.setStatus(302);
response.setHeader("location", request.getContextPath()+"/toLogin"); response.setHeader("location", request.getContextPath()+"/toLogin");
return false; return false;

View File

@ -1,5 +1,6 @@
package com.xxl.job.admin.controller.interceptor; package com.xxl.job.admin.controller.interceptor;
import com.xxl.job.admin.enums.ApiConstants;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@ -21,8 +22,8 @@ public class WebMvcConfig implements WebMvcConfigurer {
@Override @Override
public void addInterceptors(InterceptorRegistry registry) { public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(permissionInterceptor).addPathPatterns("/**"); registry.addInterceptor(permissionInterceptor).addPathPatterns("/**").excludePathPatterns("/auth/login-by-code", "/auth/refresh-token", "/auth/logout", ApiConstants.PREFIX + "/**");
registry.addInterceptor(cookieInterceptor).addPathPatterns("/**"); registry.addInterceptor(cookieInterceptor).addPathPatterns("/**").excludePathPatterns("/auth/login-by-code", "/auth/refresh-token", "/auth/logout", ApiConstants.PREFIX + "/**");
} }
} }

View File

@ -37,7 +37,7 @@ public class CookieUtil {
* @param value * @param value
* @param maxAge * @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); Cookie cookie = new Cookie(key, value);
if (domain != null) { if (domain != null) {
cookie.setDomain(domain); cookie.setDomain(domain);

View File

@ -1,13 +1,23 @@
package com.xxl.job.admin.service; 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.model.XxlJobUser;
import com.xxl.job.admin.core.util.CookieUtil; import com.xxl.job.admin.core.util.CookieUtil;
import com.xxl.job.admin.core.util.I18nUtil; import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.admin.core.util.JacksonUtil; import com.xxl.job.admin.core.util.JacksonUtil;
import com.xxl.job.admin.dao.XxlJobUserDao; 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 com.xxl.job.core.biz.model.ReturnT;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.util.DigestUtils; import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -21,17 +31,21 @@ import java.math.BigInteger;
public class LoginService { public class LoginService {
public static final String LOGIN_IDENTITY_KEY = "XXL_JOB_LOGIN_IDENTITY"; 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 @Resource
private XxlJobUserDao xxlJobUserDao; private XxlJobUserDao xxlJobUserDao;
private String makeToken(XxlJobUser xxlJobUser){ private String makeToken(XxlJobUser xxlJobUser) {
String tokenJson = JacksonUtil.writeValueAsString(xxlJobUser); String tokenJson = JacksonUtil.writeValueAsString(xxlJobUser);
String tokenHex = new BigInteger(tokenJson.getBytes()).toString(16); String tokenHex = new BigInteger(tokenJson.getBytes()).toString(16);
return tokenHex; return tokenHex;
} }
private XxlJobUser parseToken(String tokenHex){
private XxlJobUser parseToken(String tokenHex) {
XxlJobUser xxlJobUser = null; XxlJobUser xxlJobUser = null;
if (tokenHex != null) { if (tokenHex != null) {
String tokenJson = new String(new BigInteger(tokenHex, 16).toByteArray()); // username_password(md5) String tokenJson = new String(new BigInteger(tokenHex, 16).toByteArray()); // username_password(md5)
@ -41,10 +55,10 @@ public class LoginService {
} }
public ReturnT<String> login(HttpServletRequest request, HttpServletResponse response, String username, String password, boolean ifRemember){ public ReturnT<String> login(HttpServletRequest request, HttpServletResponse response, String username, String password, boolean ifRemember) {
// param // 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<String>(500, I18nUtil.getString("login_param_empty")); return new ReturnT<String>(500, I18nUtil.getString("login_param_empty"));
} }
@ -71,7 +85,7 @@ public class LoginService {
* @param request * @param request
* @param response * @param response
*/ */
public ReturnT<String> logout(HttpServletRequest request, HttpServletResponse response){ public ReturnT<String> logout(HttpServletRequest request, HttpServletResponse response) {
CookieUtil.remove(request, response, LOGIN_IDENTITY_KEY); CookieUtil.remove(request, response, LOGIN_IDENTITY_KEY);
return ReturnT.SUCCESS; return ReturnT.SUCCESS;
} }
@ -82,7 +96,7 @@ public class LoginService {
* @param request * @param request
* @return * @return
*/ */
public XxlJobUser ifLogin(HttpServletRequest request, HttpServletResponse response){ public XxlJobUser ifLogin(HttpServletRequest request, HttpServletResponse response) {
// String cookieToken = CookieUtil.getValue(request, LOGIN_IDENTITY_KEY); // String cookieToken = CookieUtil.getValue(request, LOGIN_IDENTITY_KEY);
// if (cookieToken != null) { // if (cookieToken != null) {
@ -112,4 +126,49 @@ public class LoginService {
return test; 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<OAuth2CheckTokenRespDTO> 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;
}
}
} }

View File

@ -54,7 +54,11 @@
+ '&response_type=' + responseType; + '&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) { if (!accessToken) {
// 获取 URL 中的查询参数 // 获取 URL 中的查询参数
@ -67,10 +71,10 @@
// 提交 // 提交
const redirectUri = 'http://127.0.0.1:9090/xxl-job-admin/toLogin'; // 需要修改成,你回调的地址,就是在 index.html 拼接的 redirectUri const redirectUri = 'http://127.0.0.1:9090/xxl-job-admin/toLogin'; // 需要修改成,你回调的地址,就是在 index.html 拼接的 redirectUri
$.ajax({ $.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, + '&redirectUri=' + redirectUri,
method: 'POST', method: 'POST',
success: function( result ) { success: function (result) {
if (result.code !== 0) { if (result.code !== 0) {
// layer.open({ // layer.open({
// title: I18n.system_tips, // title: I18n.system_tips,
@ -81,20 +85,15 @@
alert('获得访问令牌失败,原因:' + result.msg) alert('获得访问令牌失败,原因:' + result.msg)
return; return;
} }
// 设置到 localStorage 中 // 设置cookie
localStorage.setItem('ACCESS-TOKEN', result.data.access_token); document.cookie = "ACCESS_TOKEN=" + result.data.access_token + "; max-age=" + result.data.expires_in + "; path=/xxl-job-admin";
localStorage.setItem('REFRESH-TOKEN', result.data.refresh_token); document.cookie = "REFRESH_TOKEN=" + result.data.refresh_token + "; max-age=43000; path=/xxl-job-admin";
localStorage.setItem('EXPIRES-IN', Date.now() + result.data.expires_in * 1000);
// 跳转回首页 // 跳转回首页
window.location.href = '/xxl-job-admin'; window.location.href = '/xxl-job-admin';
} }
}) })
} }
} }
// 情况二Token失效暂未实现
else if (Date.now() > localStorage.getItem('EXPIRES-IN')) {
console.log('重新获取授权码')
}
// 情况三:已登录 // 情况三:已登录
else { else {
window.location.href = '/xxl-job-admin'; window.location.href = '/xxl-job-admin';