VYPR
Low severity3.7NVD Advisory· Published Jul 18, 2025· Updated Apr 29, 2026

CVE-2025-7789

CVE-2025-7789

Description

A vulnerability was found in Xuxueli xxl-job up to 3.1.1 and classified as problematic. Affected by this issue is the function makeToken of the file src/main/java/com/xxl/job/admin/controller/IndexController.java of the component Token Generation. The manipulation leads to password hash with insufficient computational effort. The attack may be launched remotely. The complexity of an attack is rather high. The exploitation is known to be difficult. The exploit has been disclosed to the public and may be used.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
com.xuxueli:xxl-job-adminMaven
< 3.2.03.2.0

Affected products

1
  • cpe:2.3:a:xuxueli:xxl-job:*:*:*:*:*:*:*:*
    Range: <=3.1.1

Patches

1
cb1bd548a6d9

登录认证重构:密码加密算法从Md5改为Sha256;登录态改为登录后动态随机生成;提升系统安全性;

https://github.com/xuxueli/xxl-jobxuxueliAug 23, 2025via ghsa
35 files changed · +601 513
  • doc/XXL-JOB官方文档.md+13 14 modified
    @@ -2545,20 +2545,7 @@ public void execute() {
     
     ### 7.40 版本 v3.2.0 Release Notes[规划中]
     - 1、【强化】AI任务(ollamaJobHandler)优化:针对 “model” 模型配置信息,从执行器侧文件类配置调整至调度中心“任务参数”动态配置,支持集成多模型、并结合任务动态配置切换。
    -- 2、【修复】漏洞修复(CVE-2025-7787),针对 httpJobHandler 支持配置URL白名单限制,防止服务器端请求伪造(SSRF)攻击。
    -- 3、【升级】升级多项maven依赖至较新版本,如 netty、groovy、mybatis、spring、spring-ai、dify 等;
    -- 4、【优化】登录信息页面空值处理优化,避免空值影响ftl渲染;
    -- 5、【优化】异常页面处理逻辑优化,新增兜底落地页配置;
    -- 6、【重构】ReturnT 重构,简化代码结构,提升API易用性以及可维护性;
    -- 7、【修复】合并PR-3738,修复拼写问题;
    -- 8、【修复】合并PR-3506,修复小概率情况下任务重复调度问题;
    -- 9、【修复】合并PR-3747,修复异常情况下资源泄漏风险;
    -- 10、【优化】调度中心系统日志调整,支持启动时指定 -DLOG_HOME 参数自定义日志位置;同时优化日志格式提升易读性;
    -- 11、【新增】GLUE模式(Python) 扩展,可选 "GLUE(Python3)" 或 "GLUE(Python2)" 两种模式,分别支持 python3/2 多版本;  
    -- 12、【优化】任务Bean扫描规则调整,过滤冗余不必要扫描,避免系统组件提前初始化;
    -- 13、【重构】项目结构重构,提升可维护性与易读性;
    -- 
    -- 14、【ING】登录认证重构,提升安全性。密码加密算法从Md5改为Sha256;登录态改为登录后动态随机生成;(需要针对用户表进行字段调整;同时需要重新初始化加密密码;相关SQL脚本如下;)
    +- 2、【安全】登录认证重构:密码加密算法从Md5改为Sha256;登录态改为登录后动态随机生成;提升系统安全性;(需要针对用户表进行字段调整,同时需要重新初始化密码信息;相关SQL脚本如下)
     ```
     // 1、用户表password字段需要调整长度,执行如下命令
     ALTER TABLE xxl_job_user
    @@ -2569,6 +2556,18 @@ ALTER TABLE xxl_job_user
     // 2、存量用户密码需要修改,可执行如下命令将密码初始化 “123456”;也可以自行通过 “SHA256Tool.sha256” 工具生成其他初始化密码;
     UPDATE xxl_job_user t SET t.password = '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92' WHERE t.username = {用户名};
     ```
    +- 3、【强化】GLUE模式(Python) 扩展,支持 "GLUE(Python3)" 与 "GLUE(Python2)" 两种模式,分别支持 python3/2 多版本;
    +- 4、【强化】调度中心系统日志调整,支持启动时指定 -DLOG_HOME 参数自定义日志位置;同时优化日志格式提升易读性;
    +- 5、【优化】任务Bean扫描规则调整,过滤冗余不必要扫描,避免系统组件提前初始化;
    +- 6、【优化】登录信息页面空值处理优化,避免空值影响ftl渲染;
    +- 7、【优化】异常页面处理逻辑优化,新增兜底落地页配置;
    +- 8、【重构】ReturnT 重构,简化代码结构,提升API易用性以及可维护性;
    +- 9、【重构】项目结构重构,提升可维护性与易读性;
    +- 10、【修复】漏洞修复(CVE-2025-7787),针对 httpJobHandler 支持配置URL白名单限制,防止服务器端请求伪造(SSRF)攻击。
    +- 11、【修复】合并PR-3738,修复拼写问题;
    +- 12、【修复】合并PR-3506,修复小概率情况下任务重复调度问题;
    +- 13、【修复】合并PR-3747,修复异常情况下资源泄漏风险;
    +- 14、【升级】升级多项maven依赖至较新版本,如 netty、groovy、mybatis、spring、spring-ai、dify 等;
     
     
     ### 7.41 版本 v3.2.1 Release Notes[规划中]
    
  • xxl-job-admin/src/main/java/com/xxl/job/admin/annotation/PermissionLimit.java+0 29 removed
    @@ -1,29 +0,0 @@
    -package com.xxl.job.admin.annotation;
    -
    -
    -import java.lang.annotation.ElementType;
    -import java.lang.annotation.Retention;
    -import java.lang.annotation.RetentionPolicy;
    -import java.lang.annotation.Target;
    -
    -/**
    - * 权限限制
    - * @author xuxueli 2015-12-12 18:29:02
    - */
    -@Target(ElementType.METHOD)
    -@Retention(RetentionPolicy.RUNTIME)
    -public @interface PermissionLimit {
    -	
    -	/**
    -	 * 登录拦截 (默认拦截)
    -	 */
    -	boolean limit() default true;
    -
    -	/**
    -	 * 要求管理员权限
    -	 *
    -	 * @return
    -	 */
    -	boolean adminuser() default false;
    -
    -}
    \ No newline at end of file
    
  • xxl-job-admin/src/main/java/com/xxl/job/admin/constant/Consts.java+7 0 added
    @@ -0,0 +1,7 @@
    +package com.xxl.job.admin.constant;
    +
    +public class Consts {
    +
    +    public static final String ADMIN_ROLE = "ADMIN";
    +
    +}
    
  • xxl-job-admin/src/main/java/com/xxl/job/admin/controller/biz/JobApiController.java+3 3 modified
    @@ -1,13 +1,13 @@
     package com.xxl.job.admin.controller.biz;
     
    -import com.xxl.job.admin.annotation.PermissionLimit;
     import com.xxl.job.admin.scheduler.conf.XxlJobAdminConfig;
     import com.xxl.job.core.biz.AdminBiz;
     import com.xxl.job.core.biz.model.HandleCallbackParam;
     import com.xxl.job.core.biz.model.RegistryParam;
     import com.xxl.job.core.biz.model.ReturnT;
    -import com.xxl.job.core.util.GsonTool;
     import com.xxl.job.core.util.XxlJobRemotingUtil;
    +import com.xxl.sso.core.annotation.XxlSso;
    +import com.xxl.tool.gson.GsonTool;
     import jakarta.annotation.Resource;
     import jakarta.servlet.http.HttpServletRequest;
     import org.springframework.stereotype.Controller;
    @@ -37,7 +37,7 @@ public class JobApiController {
          */
         @RequestMapping("/{uri}")
         @ResponseBody
    -    @PermissionLimit(limit=false)
    +    @XxlSso(login = false)
         public ReturnT<String> api(HttpServletRequest request, @PathVariable("uri") String uri, @RequestBody(required = false) String data) {
     
             // valid
    
  • xxl-job-admin/src/main/java/com/xxl/job/admin/controller/biz/JobCodeController.java+7 8 modified
    @@ -1,11 +1,10 @@
     package com.xxl.job.admin.controller.biz;
     
    -import com.xxl.job.admin.web.xxlsso.PermissionInterceptor;
    +import com.xxl.job.admin.mapper.XxlJobInfoMapper;
    +import com.xxl.job.admin.mapper.XxlJobLogGlueMapper;
     import com.xxl.job.admin.model.XxlJobInfo;
     import com.xxl.job.admin.model.XxlJobLogGlue;
     import com.xxl.job.admin.util.I18nUtil;
    -import com.xxl.job.admin.mapper.XxlJobInfoMapper;
    -import com.xxl.job.admin.mapper.XxlJobLogGlueMapper;
     import com.xxl.job.core.biz.model.ReturnT;
     import com.xxl.job.core.glue.GlueTypeEnum;
     import jakarta.annotation.Resource;
    @@ -44,8 +43,8 @@ public String index(HttpServletRequest request, Model model, @RequestParam("jobI
     			throw new RuntimeException(I18nUtil.getString("jobinfo_glue_gluetype_unvalid"));
     		}
     
    -		// valid permission
    -		PermissionInterceptor.validJobGroupPermission(request, jobInfo.getJobGroup());
    +		// valid jobGroup permission
    +		JobInfoController.validJobGroupPermission(request, jobInfo.getJobGroup());
     
     		// Glue类型-字典
     		model.addAttribute("GlueTypeEnum", GlueTypeEnum.values());
    @@ -74,9 +73,9 @@ public ReturnT<String> save(HttpServletRequest request,
     			return new ReturnT<String>(500, I18nUtil.getString("jobinfo_glue_jobid_unvalid"));
     		}
     
    -		// valid permission
    -		PermissionInterceptor.validJobGroupPermission(request, existsJobInfo.getJobGroup());
    -		
    +		// valid jobGroup permission
    +		JobInfoController.validJobGroupPermission(request, existsJobInfo.getJobGroup());
    +
     		// update new code
     		existsJobInfo.setGlueSource(glueSource);
     		existsJobInfo.setGlueRemark(glueRemark);
    
  • xxl-job-admin/src/main/java/com/xxl/job/admin/controller/biz/JobGroupController.java+8 7 modified
    @@ -1,6 +1,6 @@
     package com.xxl.job.admin.controller.biz;
     
    -import com.xxl.job.admin.annotation.PermissionLimit;
    +import com.xxl.job.admin.constant.Consts;
     import com.xxl.job.admin.model.XxlJobGroup;
     import com.xxl.job.admin.model.XxlJobRegistry;
     import com.xxl.job.admin.util.I18nUtil;
    @@ -9,6 +9,7 @@
     import com.xxl.job.admin.mapper.XxlJobRegistryMapper;
     import com.xxl.job.core.biz.model.ReturnT;
     import com.xxl.job.core.enums.RegistryConfig;
    +import com.xxl.sso.core.annotation.XxlSso;
     import jakarta.annotation.Resource;
     import jakarta.servlet.http.HttpServletRequest;
     import org.springframework.stereotype.Controller;
    @@ -35,14 +36,14 @@ public class JobGroupController {
     	private XxlJobRegistryMapper xxlJobRegistryMapper;
     
     	@RequestMapping
    -	@PermissionLimit(adminuser = true)
    +	@XxlSso(role = Consts.ADMIN_ROLE)
     	public String index(Model model) {
     		return "jobgroup/jobgroup.index";
     	}
     
     	@RequestMapping("/pageList")
     	@ResponseBody
    -	@PermissionLimit(adminuser = true)
    +	@XxlSso(role = Consts.ADMIN_ROLE)
     	public Map<String, Object> pageList(HttpServletRequest request,
     										@RequestParam(value = "start", required = false, defaultValue = "0") int start,
     										@RequestParam(value = "length", required = false, defaultValue = "10") int length,
    @@ -63,7 +64,7 @@ public Map<String, Object> pageList(HttpServletRequest request,
     
     	@RequestMapping("/save")
     	@ResponseBody
    -	@PermissionLimit(adminuser = true)
    +	@XxlSso(role = Consts.ADMIN_ROLE)
     	public ReturnT<String> save(XxlJobGroup xxlJobGroup){
     
     		// valid
    @@ -107,7 +108,7 @@ public ReturnT<String> save(XxlJobGroup xxlJobGroup){
     
     	@RequestMapping("/update")
     	@ResponseBody
    -	@PermissionLimit(adminuser = true)
    +	@XxlSso(role = Consts.ADMIN_ROLE)
     	public ReturnT<String> update(XxlJobGroup xxlJobGroup){
     		// valid
     		if (xxlJobGroup.getAppname()==null || xxlJobGroup.getAppname().trim().length()==0) {
    @@ -176,7 +177,7 @@ private List<String> findRegistryByAppName(String appnameParam){
     
     	@RequestMapping("/remove")
     	@ResponseBody
    -	@PermissionLimit(adminuser = true)
    +	@XxlSso(role = Consts.ADMIN_ROLE)
     	public ReturnT<String> remove(@RequestParam("id") int id){
     
     		// valid
    @@ -196,7 +197,7 @@ public ReturnT<String> remove(@RequestParam("id") int id){
     
     	@RequestMapping("/loadById")
     	@ResponseBody
    -	@PermissionLimit(adminuser = true)
    +	@XxlSso(role = Consts.ADMIN_ROLE)
     	public ReturnT<XxlJobGroup> loadById(@RequestParam("id") int id){
     		XxlJobGroup jobGroup = xxlJobGroupMapper.load(id);
     		return jobGroup!=null?ReturnT.ofSuccess(jobGroup):ReturnT.ofFail();
    
  • xxl-job-admin/src/main/java/com/xxl/job/admin/controller/biz/JobInfoController.java+69 18 modified
    @@ -1,21 +1,24 @@
     package com.xxl.job.admin.controller.biz;
     
    -import com.xxl.job.admin.web.xxlsso.PermissionInterceptor;
    -import com.xxl.job.admin.scheduler.exception.XxlJobException;
    +import com.xxl.job.admin.constant.Consts;
    +import com.xxl.job.admin.mapper.XxlJobGroupMapper;
     import com.xxl.job.admin.model.XxlJobGroup;
     import com.xxl.job.admin.model.XxlJobInfo;
    -import com.xxl.job.admin.model.XxlJobUser;
    +import com.xxl.job.admin.scheduler.exception.XxlJobException;
     import com.xxl.job.admin.scheduler.route.ExecutorRouteStrategyEnum;
     import com.xxl.job.admin.scheduler.scheduler.MisfireStrategyEnum;
     import com.xxl.job.admin.scheduler.scheduler.ScheduleTypeEnum;
     import com.xxl.job.admin.scheduler.thread.JobScheduleHelper;
    -import com.xxl.job.admin.util.I18nUtil;
    -import com.xxl.job.admin.mapper.XxlJobGroupMapper;
     import com.xxl.job.admin.service.XxlJobService;
    +import com.xxl.job.admin.util.I18nUtil;
     import com.xxl.job.core.biz.model.ReturnT;
     import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
     import com.xxl.job.core.glue.GlueTypeEnum;
     import com.xxl.job.core.util.DateUtil;
    +import com.xxl.sso.core.helper.XxlSsoHelper;
    +import com.xxl.sso.core.model.LoginInfo;
    +import com.xxl.tool.core.StringTool;
    +import com.xxl.tool.response.Response;
     import jakarta.annotation.Resource;
     import jakarta.servlet.http.HttpServletRequest;
     import org.slf4j.Logger;
    @@ -26,7 +29,10 @@
     import org.springframework.web.bind.annotation.RequestParam;
     import org.springframework.web.bind.annotation.ResponseBody;
     
    -import java.util.*;
    +import java.util.ArrayList;
    +import java.util.Date;
    +import java.util.List;
    +import java.util.Map;
     
     /**
      * index controller
    @@ -53,11 +59,11 @@ public String index(HttpServletRequest request, Model model, @RequestParam(value
     		model.addAttribute("MisfireStrategyEnum", MisfireStrategyEnum.values());	    			// 调度过期策略
     
     		// 执行器列表
    -		List<XxlJobGroup> jobGroupList_all =  xxlJobGroupMapper.findAll();
    +		List<XxlJobGroup> jobGroupListTotal =  xxlJobGroupMapper.findAll();
     
     		// filter group
    -		List<XxlJobGroup> jobGroupList = PermissionInterceptor.filterJobGroupByRole(request, jobGroupList_all);
    -		if (jobGroupList==null || jobGroupList.size()==0) {
    +		List<XxlJobGroup> jobGroupList = filterJobGroupByPermission(request, jobGroupListTotal);
    +		if (jobGroupList==null || jobGroupList.isEmpty()) {
     			throw new XxlJobException(I18nUtil.getString("jobgroup_empty"));
     		}
     
    @@ -84,22 +90,20 @@ public Map<String, Object> pageList(@RequestParam(value = "start", required = fa
     	@ResponseBody
     	public ReturnT<String> add(HttpServletRequest request, XxlJobInfo jobInfo) {
     		// valid permission
    -		PermissionInterceptor.validJobGroupPermission(request, jobInfo.getJobGroup());
    +		LoginInfo loginInfo = validJobGroupPermission(request, jobInfo.getJobGroup());
     
     		// opt
    -		XxlJobUser loginUser = PermissionInterceptor.getLoginUser(request);
    -		return xxlJobService.add(jobInfo, loginUser);
    +		return xxlJobService.add(jobInfo, loginInfo);
     	}
    -	
    +
     	@RequestMapping("/update")
     	@ResponseBody
     	public ReturnT<String> update(HttpServletRequest request, XxlJobInfo jobInfo) {
     		// valid permission
    -		PermissionInterceptor.validJobGroupPermission(request, jobInfo.getJobGroup());
    +		LoginInfo loginInfo = validJobGroupPermission(request, jobInfo.getJobGroup());
     
     		// opt
    -		XxlJobUser loginUser = PermissionInterceptor.getLoginUser(request);
    -		return xxlJobService.update(jobInfo, loginUser);
    +		return xxlJobService.update(jobInfo, loginInfo);
     	}
     	
     	@RequestMapping("/remove")
    @@ -128,9 +132,10 @@ public ReturnT<String> triggerJob(HttpServletRequest request,
     									  @RequestParam("addressList") String addressList) {
     
     		// login user
    -		XxlJobUser loginUser = PermissionInterceptor.getLoginUser(request);
    +		Response<LoginInfo> loginInfoResponse = XxlSsoHelper.loginCheckWithAttr(request);
    +
     		// trigger
    -		return xxlJobService.trigger(loginUser, id, executorParam, addressList);
    +		return xxlJobService.trigger(loginInfoResponse.getData(), id, executorParam, addressList);
     	}
     
     	@RequestMapping("/nextTriggerTime")
    @@ -160,5 +165,51 @@ public ReturnT<List<String>> nextTriggerTime(@RequestParam("scheduleType") Strin
     		return ReturnT.ofSuccess(result);
     
     	}
    +
    +
    +	// -------------------- tool --------------------
    +
    +	/**
    +	 * check if has jobgroup permission
    +	 */
    +	public static boolean hasJobGroupPermission(LoginInfo loginInfo, int jobGroup){
    +		if (XxlSsoHelper.hasRole(loginInfo, Consts.ADMIN_ROLE).isSuccess()) {
    +			return true;
    +		} else {
    +			List<String> jobGroups = (loginInfo.getExtraInfo()!=null && loginInfo.getExtraInfo().containsKey("jobGroups"))
    +					? List.of(StringTool.tokenizeToArray(loginInfo.getExtraInfo().get("jobGroups"), ",")) :new ArrayList<>();
    +			return jobGroups.contains(String.valueOf(jobGroup));
    +		}
    +	}
    +
    +	/**
    +	 * valid jobGroup permission
    +	 */
    +	public static LoginInfo validJobGroupPermission(HttpServletRequest request, int jobGroup) {
    +		Response<LoginInfo>  loginInfoResponse = XxlSsoHelper.loginCheckWithAttr(request);
    +		if (!(loginInfoResponse.isSuccess() && hasJobGroupPermission(loginInfoResponse.getData(), jobGroup))) {
    +			throw new RuntimeException(I18nUtil.getString("system_permission_limit") + "[username="+ loginInfoResponse.getData().getUserName() +"]");
    +		}
    +		return loginInfoResponse.getData();
    +	}
    +
    +	/**
    +	 * filter jobGroupList by permission
    +	 */
    +	public static List<XxlJobGroup> filterJobGroupByPermission(HttpServletRequest request, List<XxlJobGroup> jobGroupListTotal){
    +		Response<LoginInfo>  loginInfoResponse = XxlSsoHelper.loginCheckWithAttr(request);
    +
    +		if (XxlSsoHelper.hasRole(loginInfoResponse.getData(), Consts.ADMIN_ROLE).isSuccess()) {
    +			return jobGroupListTotal;
    +		} else {
    +			List<String> jobGroups = (loginInfoResponse.getData().getExtraInfo()!=null && loginInfoResponse.getData().getExtraInfo().containsKey("jobGroups"))
    +					? List.of(StringTool.tokenizeToArray(loginInfoResponse.getData().getExtraInfo().get("jobGroups"), ",")) :new ArrayList<>();
    +
    +			return jobGroupListTotal
    +					.stream()
    +					.filter(jobGroup -> jobGroups.contains(String.valueOf(jobGroup.getId())))
    +					.toList();
    +		}
    +	}
     	
     }
    
  • xxl-job-admin/src/main/java/com/xxl/job/admin/controller/biz/JobLogController.java+14 15 modified
    @@ -1,16 +1,15 @@
     package com.xxl.job.admin.controller.biz;
     
    -import com.xxl.job.admin.web.xxlsso.PermissionInterceptor;
    -import com.xxl.job.admin.scheduler.complete.XxlJobCompleter;
    -import com.xxl.job.admin.scheduler.exception.XxlJobException;
    +import com.xxl.job.admin.mapper.XxlJobGroupMapper;
    +import com.xxl.job.admin.mapper.XxlJobInfoMapper;
    +import com.xxl.job.admin.mapper.XxlJobLogMapper;
     import com.xxl.job.admin.model.XxlJobGroup;
     import com.xxl.job.admin.model.XxlJobInfo;
     import com.xxl.job.admin.model.XxlJobLog;
    +import com.xxl.job.admin.scheduler.complete.XxlJobCompleter;
    +import com.xxl.job.admin.scheduler.exception.XxlJobException;
     import com.xxl.job.admin.scheduler.scheduler.XxlJobScheduler;
     import com.xxl.job.admin.util.I18nUtil;
    -import com.xxl.job.admin.mapper.XxlJobGroupMapper;
    -import com.xxl.job.admin.mapper.XxlJobInfoMapper;
    -import com.xxl.job.admin.mapper.XxlJobLogMapper;
     import com.xxl.job.core.biz.ExecutorBiz;
     import com.xxl.job.core.biz.model.KillParam;
     import com.xxl.job.core.biz.model.LogParam;
    @@ -54,11 +53,11 @@ public class JobLogController {
     	public String index(HttpServletRequest request, Model model, @RequestParam(value = "jobId", required = false, defaultValue = "0") Integer jobId) {
     
     		// 执行器列表
    -		List<XxlJobGroup> jobGroupList_all =  xxlJobGroupMapper.findAll();
    +		List<XxlJobGroup> jobGroupListTotal =  xxlJobGroupMapper.findAll();
     
     		// filter group
    -		List<XxlJobGroup> jobGroupList = PermissionInterceptor.filterJobGroupByRole(request, jobGroupList_all);
    -		if (jobGroupList==null || jobGroupList.size()==0) {
    +		List<XxlJobGroup> jobGroupList = JobInfoController.filterJobGroupByPermission(request, jobGroupListTotal);
    +		if (jobGroupList==null || jobGroupList.isEmpty()) {
     			throw new XxlJobException(I18nUtil.getString("jobgroup_empty"));
     		}
     
    @@ -74,7 +73,7 @@ public String index(HttpServletRequest request, Model model, @RequestParam(value
     			model.addAttribute("jobInfo", jobInfo);
     
     			// valid permission
    -			PermissionInterceptor.validJobGroupPermission(request, jobInfo.getJobGroup());
    +			JobInfoController.validJobGroupPermission(request, jobInfo.getJobGroup());
     		}
     
     		return "joblog/joblog.index";
    @@ -97,9 +96,9 @@ public Map<String, Object> pageList(HttpServletRequest request,
     										@RequestParam("logStatus") int logStatus,
     										@RequestParam("filterTime") String filterTime) {
     
    -		// valid permission
    -		PermissionInterceptor.validJobGroupPermission(request, jobGroup);	// 仅管理员支持查询全部;普通用户仅支持查询有权限的 jobGroup
    -		
    +		// valid jobGroup permission
    +		JobInfoController.validJobGroupPermission(request, jobGroup);
    +
     		// parse param
     		Date triggerTimeStart = null;
     		Date triggerTimeEnd = null;
    @@ -133,7 +132,7 @@ public String logDetailPage(HttpServletRequest request, @RequestParam("id") int
     		}
     
     		// valid permission
    -		PermissionInterceptor.validJobGroupPermission(request, jobLog.getJobGroup());
    +		JobInfoController.validJobGroupPermission(request, jobLog.getJobGroup());
     
     		// data
             model.addAttribute("triggerCode", jobLog.getTriggerCode());
    @@ -249,7 +248,7 @@ public ReturnT<String> clearLog(HttpServletRequest request,
     									@RequestParam("jobId") int jobId,
     									@RequestParam("type") int type){
     		// valid permission
    -		PermissionInterceptor.validJobGroupPermission(request, jobGroup);
    +		JobInfoController.validJobGroupPermission(request, jobGroup);
     
     		// opt
     		Date clearBeforeTime = null;
    
  • xxl-job-admin/src/main/java/com/xxl/job/admin/controller/biz/JobUserController.java+16 13 modified
    @@ -1,14 +1,17 @@
     package com.xxl.job.admin.controller.biz;
     
    -import com.xxl.job.admin.annotation.PermissionLimit;
    +import com.xxl.job.admin.constant.Consts;
     import com.xxl.job.admin.mapper.XxlJobGroupMapper;
     import com.xxl.job.admin.mapper.XxlJobUserMapper;
     import com.xxl.job.admin.model.XxlJobGroup;
     import com.xxl.job.admin.model.XxlJobUser;
     import com.xxl.job.admin.util.I18nUtil;
    -import com.xxl.job.admin.web.xxlsso.PermissionInterceptor;
     import com.xxl.job.core.biz.model.ReturnT;
    +import com.xxl.sso.core.annotation.XxlSso;
    +import com.xxl.sso.core.helper.XxlSsoHelper;
    +import com.xxl.sso.core.model.LoginInfo;
     import com.xxl.tool.encrypt.SHA256Tool;
    +import com.xxl.tool.response.Response;
     import jakarta.annotation.Resource;
     import jakarta.servlet.http.HttpServletRequest;
     import org.springframework.stereotype.Controller;
    @@ -35,7 +38,7 @@ public class JobUserController {
         private XxlJobGroupMapper xxlJobGroupMapper;
     
         @RequestMapping
    -    @PermissionLimit(adminuser = true)
    +    @XxlSso(role = Consts.ADMIN_ROLE)
         public String index(Model model) {
     
             // 执行器列表
    @@ -47,7 +50,7 @@ public String index(Model model) {
     
         @RequestMapping("/pageList")
         @ResponseBody
    -    @PermissionLimit(adminuser = true)
    +    @XxlSso(role = Consts.ADMIN_ROLE)
         public Map<String, Object> pageList(@RequestParam(value = "start", required = false, defaultValue = "0") int start,
                                             @RequestParam(value = "length", required = false, defaultValue = "10") int length,
                                             @RequestParam("username") String username,
    @@ -74,7 +77,7 @@ public Map<String, Object> pageList(@RequestParam(value = "start", required = fa
     
         @RequestMapping("/add")
         @ResponseBody
    -    @PermissionLimit(adminuser = true)
    +    @XxlSso(role = Consts.ADMIN_ROLE)
         public ReturnT<String> add(XxlJobUser xxlJobUser) {
     
             // valid username
    @@ -110,12 +113,12 @@ public ReturnT<String> add(XxlJobUser xxlJobUser) {
     
         @RequestMapping("/update")
         @ResponseBody
    -    @PermissionLimit(adminuser = true)
    +    @XxlSso(role = Consts.ADMIN_ROLE)
         public ReturnT<String> update(HttpServletRequest request, XxlJobUser xxlJobUser) {
     
             // avoid opt login seft
    -        XxlJobUser loginUser = PermissionInterceptor.getLoginUser(request);
    -        if (loginUser.getUsername().equals(xxlJobUser.getUsername())) {
    +        Response<LoginInfo> loginInfoResponse = XxlSsoHelper.loginCheckWithAttr(request);
    +        if (loginInfoResponse.getData().getUserName().equals(xxlJobUser.getUsername())) {
                 return ReturnT.ofFail(I18nUtil.getString("user_update_loginuser_limit"));
             }
     
    @@ -139,12 +142,12 @@ public ReturnT<String> update(HttpServletRequest request, XxlJobUser xxlJobUser)
     
         @RequestMapping("/remove")
         @ResponseBody
    -    @PermissionLimit(adminuser = true)
    +    @XxlSso(role = Consts.ADMIN_ROLE)
         public ReturnT<String> remove(HttpServletRequest request, @RequestParam("id") int id) {
     
             // avoid opt login seft
    -        XxlJobUser loginUser = PermissionInterceptor.getLoginUser(request);
    -        if (loginUser.getId() == id) {
    +        Response<LoginInfo> loginInfoResponse = XxlSsoHelper.loginCheckWithAttr(request);
    +        if (Integer.parseInt(loginInfoResponse.getData().getUserId()) == id) {
                 return ReturnT.ofFail(I18nUtil.getString("user_update_loginuser_limit"));
             }
     
    @@ -175,8 +178,8 @@ public ReturnT<String> updatePwd(HttpServletRequest request,
             String passwordHash = SHA256Tool.sha256(password);
     
             // valid old pwd
    -        XxlJobUser loginUser = PermissionInterceptor.getLoginUser(request);
    -        XxlJobUser existUser = xxlJobUserMapper.loadByUserName(loginUser.getUsername());
    +        Response<LoginInfo> loginInfoResponse = XxlSsoHelper.loginCheckWithAttr(request);
    +        XxlJobUser existUser = xxlJobUserMapper.loadByUserName(loginInfoResponse.getData().getUserName());
             if (!oldPasswordHash.equals(existUser.getPassword())) {
                 return ReturnT.ofFail(I18nUtil.getString("change_pwd_field_oldpwd") + I18nUtil.getString("system_unvalid"));
             }
    
  • xxl-job-admin/src/main/java/com/xxl/job/admin/controller/login/LoginController.java+54 20 modified
    @@ -1,8 +1,16 @@
     package com.xxl.job.admin.controller.login;
     
    -import com.xxl.job.admin.annotation.PermissionLimit;
    -import com.xxl.job.admin.service.impl.LoginService;
    +import com.xxl.job.admin.mapper.XxlJobUserMapper;
    +import com.xxl.job.admin.model.XxlJobUser;
    +import com.xxl.job.admin.util.I18nUtil;
     import com.xxl.job.core.biz.model.ReturnT;
    +import com.xxl.sso.core.annotation.XxlSso;
    +import com.xxl.sso.core.helper.XxlSsoHelper;
    +import com.xxl.sso.core.model.LoginInfo;
    +import com.xxl.tool.core.StringTool;
    +import com.xxl.tool.encrypt.SHA256Tool;
    +import com.xxl.tool.id.UUIDTool;
    +import com.xxl.tool.response.Response;
     import jakarta.annotation.Resource;
     import jakarta.servlet.http.HttpServletRequest;
     import jakarta.servlet.http.HttpServletResponse;
    @@ -22,39 +30,65 @@
     @RequestMapping("/auth")
     public class LoginController {
     
    -
     	@Resource
    -	private LoginService loginService;
    +	private XxlJobUserMapper xxlJobUserMapper;
     
    +	@RequestMapping("/login")
    +	@XxlSso(login = false)
    +	public ModelAndView login(HttpServletRequest request, HttpServletResponse response, ModelAndView modelAndView) {
     
    -	@RequestMapping("/toLogin")
    -	@PermissionLimit(limit=false)
    -	public ModelAndView toLogin(HttpServletRequest request, HttpServletResponse response, ModelAndView modelAndView) {
    -		if (loginService.ifLogin(request, response) != null) {
    +		// xxl-sso, logincheck
    +		Response<LoginInfo> loginInfoResponse = XxlSsoHelper.loginCheckWithCookie(request, response);
    +		if (loginInfoResponse.isSuccess()) {
     			modelAndView.setView(new RedirectView("/",true,false));
     			return modelAndView;
     		}
    +
     		return new ModelAndView("login");
     	}
     
    -	@RequestMapping(value="/login", method=RequestMethod.POST)
    +	@RequestMapping(value="/doLogin", method=RequestMethod.POST)
     	@ResponseBody
    -	@PermissionLimit(limit=false)
    -	public ReturnT<String> loginDo(HttpServletRequest request,
    -								   HttpServletResponse response,
    -								   @RequestParam("userName") String userName,
    -								   @RequestParam("password") String password,
    -								   @RequestParam(value = "ifRemember", required = false) String ifRemember){
    -
    -		boolean ifRem = (ifRemember!=null && ifRemember.trim().length()>0 && "on".equals(ifRemember))?true:false;
    -		return loginService.login(request, response, userName, password, ifRem);
    +	@XxlSso(login = false)
    +	public ReturnT<String> doLogin(HttpServletRequest request,
    +									HttpServletResponse response,
    +									@RequestParam("userName") String userName,
    +									@RequestParam("password") String password,
    +									@RequestParam(value = "ifRemember", required = false) String ifRemember){
    +
    +		// param
    +		boolean ifRem = StringTool.isNotBlank(ifRemember) && "on".equals(ifRemember);
    +		if (StringTool.isBlank(userName) || StringTool.isBlank(password)){
    +			return ReturnT.ofFail( I18nUtil.getString("login_param_empty") );
    +		}
    +
    +		// valid user、status
    +		XxlJobUser xxlJobUser = xxlJobUserMapper.loadByUserName(userName);
    +		if (xxlJobUser == null) {
    +			return ReturnT.ofFail( I18nUtil.getString("login_param_unvalid") );
    +		}
    +
    +		// valid passowrd
    +		String passwordHash = SHA256Tool.sha256(password);
    +		if (!passwordHash.equals(xxlJobUser.getPassword())) {
    +			return ReturnT.ofFail( I18nUtil.getString("login_param_unvalid") );
    +		}
    +
    +		// xxl-sso, do login
    +		LoginInfo loginInfo = new LoginInfo(String.valueOf(xxlJobUser.getId()), UUIDTool.getSimpleUUID());
    +		Response<String> result= XxlSsoHelper.loginWithCookie(loginInfo, response, ifRem);
    +
    +		return ReturnT.of(result.getCode(), result.getMsg());
     	}
     
     	@RequestMapping(value="/logout", method=RequestMethod.POST)
     	@ResponseBody
    -	@PermissionLimit(limit=false)
    +	@XxlSso(login = false)
     	public ReturnT<String> logout(HttpServletRequest request, HttpServletResponse response){
    -		return loginService.logout(request, response);
    +		// xxl-sso, do logout
    +		Response<String> result = XxlSsoHelper.logoutWithCookie(request, response);
    +
    +		return ReturnT.of(result.getCode(), result.getMsg());
     	}
     
     }
    
  • xxl-job-admin/src/main/java/com/xxl/job/admin/mapper/XxlJobUserMapper.java+5 0 modified
    @@ -1,6 +1,7 @@
     package com.xxl.job.admin.mapper;
     
     import com.xxl.job.admin.model.XxlJobUser;
    +import com.xxl.tool.response.Response;
     import org.apache.ibatis.annotations.Mapper;
     import org.apache.ibatis.annotations.Param;
     import java.util.List;
    @@ -22,10 +23,14 @@ public int pageListCount(@Param("offset") int offset,
     
     	public XxlJobUser loadByUserName(@Param("username") String username);
     
    +	public XxlJobUser loadById(@Param("id") int id);
    +
     	public int save(XxlJobUser xxlJobUser);
     
     	public int update(XxlJobUser xxlJobUser);
     	
     	public int delete(@Param("id") int id);
     
    +	public int updateToken(@Param("id") int id, @Param("token") String token);
    +
     }
    
  • xxl-job-admin/src/main/java/com/xxl/job/admin/model/XxlJobUser.java+10 1 modified
    @@ -10,8 +10,9 @@ public class XxlJobUser {
     	private int id;
     	private String username;		// 账号
     	private String password;		// 密码
    +	private String token;			// 登录token
     	private int role;				// 角色:0-普通用户、1-管理员
    -	private String permission;	// 权限:执行器ID列表,多个逗号分割
    +	private String permission;		// 权限:执行器ID列表,多个逗号分割
     
     	public int getId() {
     		return id;
    @@ -37,6 +38,14 @@ public void setPassword(String password) {
     		this.password = password;
     	}
     
    +	public String getToken() {
    +		return token;
    +	}
    +
    +	public void setToken(String token) {
    +		this.token = token;
    +	}
    +
     	public int getRole() {
     		return role;
     	}
    
  • xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/LoginService.java+0 111 removed
    @@ -1,111 +0,0 @@
    -package com.xxl.job.admin.service.impl;
    -
    -import com.xxl.job.admin.mapper.XxlJobUserMapper;
    -import com.xxl.job.admin.model.XxlJobUser;
    -import com.xxl.job.admin.util.CookieUtil;
    -import com.xxl.job.admin.util.I18nUtil;
    -import com.xxl.job.core.biz.model.ReturnT;
    -import com.xxl.job.core.util.GsonTool;
    -import com.xxl.tool.encrypt.SHA256Tool;
    -import jakarta.annotation.Resource;
    -import jakarta.servlet.http.HttpServletRequest;
    -import jakarta.servlet.http.HttpServletResponse;
    -import org.springframework.stereotype.Service;
    -
    -import java.math.BigInteger;
    -
    -/**
    - * @author xuxueli 2019-05-04 22:13:264
    - */
    -@Service
    -public class LoginService {
    -
    -    public static final String LOGIN_IDENTITY_KEY = "XXL_JOB_LOGIN_IDENTITY";
    -
    -    @Resource
    -    private XxlJobUserMapper xxlJobUserMapper;
    -
    -
    -    // ---------------------- token tool ----------------------
    -
    -    private String makeToken(XxlJobUser xxlJobUser){
    -        String tokenJson = GsonTool.toJson(xxlJobUser);
    -        String tokenHex = new BigInteger(tokenJson.getBytes()).toString(16);
    -        return tokenHex;
    -    }
    -    private XxlJobUser parseToken(String tokenHex){
    -        XxlJobUser xxlJobUser = null;
    -        if (tokenHex != null) {
    -            String tokenJson = new String(new BigInteger(tokenHex, 16).toByteArray());      // username_password(md5)
    -            xxlJobUser = GsonTool.fromJson(tokenJson, XxlJobUser.class);
    -        }
    -        return xxlJobUser;
    -    }
    -
    -
    -    // ---------------------- login tool, with cookie and db ----------------------
    -
    -    public ReturnT<String> 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){
    -            return new ReturnT<String>(500, I18nUtil.getString("login_param_empty"));
    -        }
    -
    -        // valid passowrd
    -        XxlJobUser xxlJobUser = xxlJobUserMapper.loadByUserName(username);
    -        if (xxlJobUser == null) {
    -            return new ReturnT<String>(500, I18nUtil.getString("login_param_unvalid"));
    -        }
    -        String passwordHash = SHA256Tool.sha256(password);
    -        if (!passwordHash.equals(xxlJobUser.getPassword())) {
    -            return new ReturnT<String>(500, I18nUtil.getString("login_param_unvalid"));
    -        }
    -
    -        String loginToken = makeToken(xxlJobUser);
    -
    -        // do login
    -        CookieUtil.set(response, LOGIN_IDENTITY_KEY, loginToken, ifRemember);
    -        return ReturnT.ofSuccess();
    -    }
    -
    -    /**
    -     * logout
    -     *
    -     * @param request
    -     * @param response
    -     */
    -    public ReturnT<String> logout(HttpServletRequest request, HttpServletResponse response){
    -        CookieUtil.remove(request, response, LOGIN_IDENTITY_KEY);
    -        return ReturnT.ofSuccess();
    -    }
    -
    -    /**
    -     * logout
    -     *
    -     * @param request
    -     * @return
    -     */
    -    public XxlJobUser ifLogin(HttpServletRequest request, HttpServletResponse response){
    -        String cookieToken = CookieUtil.getValue(request, LOGIN_IDENTITY_KEY);
    -        if (cookieToken != null) {
    -            XxlJobUser cookieUser = null;
    -            try {
    -                cookieUser = parseToken(cookieToken);
    -            } catch (Exception e) {
    -                logout(request, response);
    -            }
    -            if (cookieUser != null) {
    -                XxlJobUser dbUser = xxlJobUserMapper.loadByUserName(cookieUser.getUsername());
    -                if (dbUser != null) {
    -                    if (cookieUser.getPassword().equals(dbUser.getPassword())) {
    -                        return dbUser;
    -                    }
    -                }
    -            }
    -        }
    -        return null;
    -    }
    -
    -
    -}
    
  • xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/XxlJobServiceImpl.java+15 21 modified
    @@ -1,23 +1,25 @@
     package com.xxl.job.admin.service.impl;
     
    -import com.xxl.job.admin.scheduler.cron.CronExpression;
    +import com.xxl.job.admin.controller.biz.JobInfoController;
    +import com.xxl.job.admin.mapper.*;
     import com.xxl.job.admin.model.XxlJobGroup;
     import com.xxl.job.admin.model.XxlJobInfo;
     import com.xxl.job.admin.model.XxlJobLogReport;
     import com.xxl.job.admin.model.XxlJobUser;
    +import com.xxl.job.admin.scheduler.cron.CronExpression;
     import com.xxl.job.admin.scheduler.route.ExecutorRouteStrategyEnum;
     import com.xxl.job.admin.scheduler.scheduler.MisfireStrategyEnum;
     import com.xxl.job.admin.scheduler.scheduler.ScheduleTypeEnum;
     import com.xxl.job.admin.scheduler.thread.JobScheduleHelper;
     import com.xxl.job.admin.scheduler.thread.JobTriggerPoolHelper;
     import com.xxl.job.admin.scheduler.trigger.TriggerTypeEnum;
    -import com.xxl.job.admin.util.I18nUtil;
    -import com.xxl.job.admin.mapper.*;
     import com.xxl.job.admin.service.XxlJobService;
    +import com.xxl.job.admin.util.I18nUtil;
     import com.xxl.job.core.biz.model.ReturnT;
     import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
     import com.xxl.job.core.glue.GlueTypeEnum;
     import com.xxl.job.core.util.DateUtil;
    +import com.xxl.sso.core.model.LoginInfo;
     import jakarta.annotation.Resource;
     import org.slf4j.Logger;
     import org.slf4j.LoggerFactory;
    @@ -61,7 +63,7 @@ public Map<String, Object> pageList(int start, int length, int jobGroup, int tri
     	}
     
     	@Override
    -	public ReturnT<String> add(XxlJobInfo jobInfo, XxlJobUser loginUser) {
    +	public ReturnT<String> add(XxlJobInfo jobInfo, LoginInfo loginInfo) {
     
     		// valid base
     		XxlJobGroup group = xxlJobGroupMapper.load(jobInfo.getJobGroup());
    @@ -131,7 +133,8 @@ public ReturnT<String> add(XxlJobInfo jobInfo, XxlJobUser loginUser) {
     						return new ReturnT<String>(ReturnT.FAIL_CODE,
     								MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_not_found")), childJobIdItem));
     					}
    -					if (!loginUser.validPermission(childJobInfo.getJobGroup())) {
    +					// valid jobGroup permission
    +					if (!JobInfoController.hasJobGroupPermission(loginInfo, childJobInfo.getJobGroup())) {
     						return new ReturnT<String>(ReturnT.FAIL_CODE,
     								MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_permission_limit")), childJobIdItem));
     					}
    @@ -175,7 +178,7 @@ private boolean isNumeric(String str){
     	}
     
     	@Override
    -	public ReturnT<String> update(XxlJobInfo jobInfo, XxlJobUser loginUser) {
    +	public ReturnT<String> update(XxlJobInfo jobInfo, LoginInfo loginInfo) {
     
     		// valid base
     		if (jobInfo.getJobDesc()==null || jobInfo.getJobDesc().trim().length()==0) {
    @@ -236,7 +239,8 @@ public ReturnT<String> update(XxlJobInfo jobInfo, XxlJobUser loginUser) {
     						return new ReturnT<String>(ReturnT.FAIL_CODE,
     								MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_not_found")), childJobIdItem));
     					}
    -					if (!loginUser.validPermission(childJobInfo.getJobGroup())) {
    +					// valid jobGroup permission
    +					if (!JobInfoController.hasJobGroupPermission(loginInfo, childJobInfo.getJobGroup())) {
     						return new ReturnT<String>(ReturnT.FAIL_CODE,
     								MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_permission_limit")), childJobIdItem));
     					}
    @@ -378,16 +382,17 @@ public ReturnT<String> stop(int id) {
     
     
     	@Override
    -	public ReturnT<String> trigger(XxlJobUser loginUser, int jobId, String executorParam, String addressList) {
    +	public ReturnT<String> trigger(LoginInfo loginInfo, int jobId, String executorParam, String addressList) {
     		// permission
    -		if (loginUser == null) {
    +		if (loginInfo == null) {
     			return ReturnT.ofFail(I18nUtil.getString("system_permission_limit"));
     		}
     		XxlJobInfo xxlJobInfo = xxlJobInfoMapper.loadById(jobId);
     		if (xxlJobInfo == null) {
     			return ReturnT.ofFail(I18nUtil.getString("jobinfo_glue_jobid_unvalid"));
     		}
    -		if (!hasPermission(loginUser, xxlJobInfo.getJobGroup())) {
    +
    +		if (!JobInfoController.hasJobGroupPermission(loginInfo, xxlJobInfo.getJobGroup())) {
     			return ReturnT.ofFail(I18nUtil.getString("system_permission_limit"));
     		}
     
    @@ -400,17 +405,6 @@ public ReturnT<String> trigger(XxlJobUser loginUser, int jobId, String executorP
     		return ReturnT.ofSuccess();
     	}
     
    -	private boolean hasPermission(XxlJobUser loginUser, int jobGroup){
    -		if (loginUser.getRole() == 1) {
    -			return true;
    -		}
    -		List<String> groupIdStrs = new ArrayList<>();
    -		if (loginUser.getPermission()!=null && loginUser.getPermission().trim().length()>0) {
    -			groupIdStrs = Arrays.asList(loginUser.getPermission().trim().split(","));
    -		}
    -		return groupIdStrs.contains(String.valueOf(jobGroup));
    -	}
    -
     	@Override
     	public Map<String, Object> dashboardInfo() {
     
    
  • xxl-job-admin/src/main/java/com/xxl/job/admin/service/XxlJobService.java+5 4 modified
    @@ -4,6 +4,7 @@
     import com.xxl.job.admin.model.XxlJobInfo;
     import com.xxl.job.admin.model.XxlJobUser;
     import com.xxl.job.core.biz.model.ReturnT;
    +import com.xxl.sso.core.model.LoginInfo;
     
     import java.util.Date;
     import java.util.Map;
    @@ -34,15 +35,15 @@ public interface XxlJobService {
     	 * @param jobInfo
     	 * @return
     	 */
    -	public ReturnT<String> add(XxlJobInfo jobInfo, XxlJobUser loginUser);
    +	public ReturnT<String> add(XxlJobInfo jobInfo, LoginInfo loginInfo);
     
     	/**
     	 * update job
     	 *
     	 * @param jobInfo
     	 * @return
     	 */
    -	public ReturnT<String> update(XxlJobInfo jobInfo, XxlJobUser loginUser);
    +	public ReturnT<String> update(XxlJobInfo jobInfo, LoginInfo loginInfo);
     
     	/**
     	 * remove job
    @@ -71,13 +72,13 @@ public interface XxlJobService {
     	/**
     	 * trigger
     	 *
    -	 * @param loginUser
    +	 * @param loginInfo
     	 * @param jobId
     	 * @param executorParam
     	 * @param addressList
     	 * @return
     	 */
    -	public ReturnT<String> trigger(XxlJobUser loginUser, int jobId, String executorParam, String addressList);
    +	public ReturnT<String> trigger(LoginInfo loginInfo, int jobId, String executorParam, String addressList);
     
     	/**
     	 * dashboard info
    
  • xxl-job-admin/src/main/java/com/xxl/job/admin/util/I18nUtil.java+2 1 modified
    @@ -1,7 +1,7 @@
     package com.xxl.job.admin.util;
     
     import com.xxl.job.admin.scheduler.conf.XxlJobAdminConfig;
    -import com.xxl.job.core.util.GsonTool;
    +import com.xxl.tool.gson.GsonTool;
     import org.slf4j.Logger;
     import org.slf4j.LoggerFactory;
     import org.springframework.core.io.ClassPathResource;
    @@ -76,4 +76,5 @@ public static String getMultString(String... keys) {
             return GsonTool.toJson(map);
         }
     
    +
     }
    
  • xxl-job-admin/src/main/java/com/xxl/job/admin/util/old/JacksonUtil.java+1 1 modified
    @@ -1,4 +1,4 @@
    -//package com.xxl.job.admin.util;
    +//package com.xxl.job.admin.util.old;
     //
     //import com.fasterxml.jackson.core.JsonGenerationException;
     //import com.fasterxml.jackson.core.JsonParseException;
    
  • xxl-job-admin/src/main/java/com/xxl/job/admin/web/interceptor/CommonDataInterceptor.java+2 1 modified
    @@ -5,6 +5,7 @@
     import jakarta.servlet.http.Cookie;
     import jakarta.servlet.http.HttpServletRequest;
     import jakarta.servlet.http.HttpServletResponse;
    +import org.springframework.context.annotation.Configuration;
     import org.springframework.stereotype.Component;
     import org.springframework.web.servlet.AsyncHandlerInterceptor;
     import org.springframework.web.servlet.ModelAndView;
    @@ -18,7 +19,7 @@
      *
      * @author xuxueli 2015-12-12 18:09:04
      */
    -@Component
    +@Configuration
     public class CommonDataInterceptor implements WebMvcConfigurer {
     
     	@Override
    
  • xxl-job-admin/src/main/java/com/xxl/job/admin/web/xxlsso/PermissionInterceptor.java+0 131 removed
    @@ -1,131 +0,0 @@
    -package com.xxl.job.admin.web.xxlsso;
    -
    -import com.xxl.job.admin.annotation.PermissionLimit;
    -import com.xxl.job.admin.model.XxlJobGroup;
    -import com.xxl.job.admin.model.XxlJobUser;
    -import com.xxl.job.admin.util.I18nUtil;
    -import com.xxl.job.admin.service.impl.LoginService;
    -import jakarta.annotation.Resource;
    -import jakarta.servlet.http.HttpServletRequest;
    -import jakarta.servlet.http.HttpServletResponse;
    -import org.springframework.stereotype.Component;
    -import org.springframework.web.method.HandlerMethod;
    -import org.springframework.web.servlet.AsyncHandlerInterceptor;
    -
    -import java.util.ArrayList;
    -import java.util.Arrays;
    -import java.util.List;
    -
    -/**
    - * 权限拦截
    - *
    - * @author xuxueli 2015-12-12 18:09:04
    - */
    -@Component
    -public class PermissionInterceptor implements AsyncHandlerInterceptor {
    -
    -	@Resource
    -	private LoginService loginService;
    -
    -	@Override
    -	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    -		
    -		if (!(handler instanceof HandlerMethod)) {
    -			return true;	// proceed with the next interceptor
    -		}
    -
    -		// if need login
    -		boolean needLogin = true;
    -		boolean needAdminuser = false;
    -		HandlerMethod method = (HandlerMethod)handler;
    -		PermissionLimit permission = method.getMethodAnnotation(PermissionLimit.class);
    -		if (permission!=null) {
    -			needLogin = permission.limit();
    -			needAdminuser = permission.adminuser();
    -		}
    -
    -		if (needLogin) {
    -			XxlJobUser loginUser = loginService.ifLogin(request, response);
    -			if (loginUser == null) {
    -				response.setStatus(302);
    -				response.setHeader("location", request.getContextPath()+"/auth/toLogin");
    -				return false;
    -			}
    -			if (needAdminuser && loginUser.getRole()!=1) {
    -				throw new RuntimeException(I18nUtil.getString("system_permission_limit"));
    -			}
    -
    -			// set loginUser, with request
    -			setLoginUser(request, loginUser);
    -		}
    -
    -		return true;	// proceed with the next interceptor
    -	}
    -
    -
    -	// -------------------- permission tool --------------------
    -
    -	/**
    -	 * set loginUser
    -	 *
    -	 * @param request
    -	 * @param loginUser
    -	 */
    -	private static void setLoginUser(HttpServletRequest request, XxlJobUser loginUser){
    -		request.setAttribute("loginUser", loginUser);
    -	}
    -
    -	/**
    -	 * get loginUser
    -	 *
    -	 * @param request
    -	 * @return
    -	 */
    -	public static XxlJobUser getLoginUser(HttpServletRequest request){
    -		XxlJobUser loginUser = (XxlJobUser) request.getAttribute("loginUser");	// get loginUser, with request
    -		return loginUser;
    -	}
    -
    -	/**
    -	 * valid permission by JobGroup
    -	 *
    -	 * @param request
    -	 * @param jobGroup
    -	 */
    -	public static void validJobGroupPermission(HttpServletRequest request, int jobGroup) {
    -		XxlJobUser loginUser = getLoginUser(request);
    -		if (!loginUser.validPermission(jobGroup)) {
    -			throw new RuntimeException(I18nUtil.getString("system_permission_limit") + "[username="+ loginUser.getUsername() +"]");
    -		}
    -	}
    -
    -	/**
    -	 * filter XxlJobGroup by role
    -	 *
    -	 * @param request
    -	 * @param jobGroupList_all
    -	 * @return
    -	 */
    -	public static List<XxlJobGroup> filterJobGroupByRole(HttpServletRequest request, List<XxlJobGroup> jobGroupList_all){
    -		List<XxlJobGroup> jobGroupList = new ArrayList<>();
    -		if (jobGroupList_all!=null && jobGroupList_all.size()>0) {
    -			XxlJobUser loginUser = PermissionInterceptor.getLoginUser(request);
    -			if (loginUser.getRole() == 1) {
    -				jobGroupList = jobGroupList_all;
    -			} else {
    -				List<String> groupIdStrs = new ArrayList<>();
    -				if (loginUser.getPermission()!=null && loginUser.getPermission().trim().length()>0) {
    -					groupIdStrs = Arrays.asList(loginUser.getPermission().trim().split(","));
    -				}
    -				for (XxlJobGroup groupItem:jobGroupList_all) {
    -					if (groupIdStrs.contains(String.valueOf(groupItem.getId()))) {
    -						jobGroupList.add(groupItem);
    -					}
    -				}
    -			}
    -		}
    -		return jobGroupList;
    -	}
    -
    -	
    -}
    
  • xxl-job-admin/src/main/java/com/xxl/job/admin/web/xxlsso/SimpleLoginStore.java+84 0 added
    @@ -0,0 +1,84 @@
    +package com.xxl.job.admin.web.xxlsso;
    +
    +import com.xxl.job.admin.constant.Consts;
    +import com.xxl.job.admin.mapper.XxlJobUserMapper;
    +import com.xxl.job.admin.model.XxlJobUser;
    +import com.xxl.sso.core.model.LoginInfo;
    +import com.xxl.sso.core.store.LoginStore;
    +import com.xxl.tool.core.MapTool;
    +import com.xxl.tool.response.Response;
    +import jakarta.annotation.Resource;
    +import org.springframework.stereotype.Component;
    +
    +import java.util.List;
    +import java.util.Map;
    +
    +/**
    + * Simple LoginStore
    + *
    + * 1、store by database;
    + * 2、If you have higher performance requirements, it is recommended to use RedisLoginStore;
    + *
    + * @author xuxueli 2025-08-03
    + */
    +@Component
    +public class SimpleLoginStore implements LoginStore {
    +
    +
    +    @Resource
    +    private XxlJobUserMapper xxlJobUserMapper;
    +
    +
    +    @Override
    +    public Response<String> set(LoginInfo loginInfo) {
    +
    +        // parse token-signature
    +        String token_sign = loginInfo.getSignature();
    +
    +        // write token by UserId
    +        int ret = xxlJobUserMapper.updateToken(Integer.parseInt(loginInfo.getUserId()), token_sign);
    +        return ret > 0 ? Response.ofSuccess() : Response.ofFail("token set fail");
    +    }
    +
    +    @Override
    +    public Response<String> update(LoginInfo loginInfo) {
    +        return Response.ofFail("not support");
    +    }
    +
    +    @Override
    +    public Response<String> remove(String userId) {
    +        // delete token-signature
    +        int ret = xxlJobUserMapper.updateToken(Integer.parseInt(userId), "");
    +        return ret > 0 ? Response.ofSuccess() : Response.ofFail("token remove fail");
    +    }
    +
    +    /**
    +     * check through DB query
    +     */
    +    @Override
    +    public Response<LoginInfo> get(String userId) {
    +
    +        // load login-user
    +        XxlJobUser user = xxlJobUserMapper.loadById(Integer.parseInt(userId));
    +        if (user == null) {
    +            return Response.ofFail("userId invalid.");
    +        }
    +
    +        // parse role
    +        List<String> roleList = user.getRole()==1? List.of(Consts.ADMIN_ROLE):null;
    +
    +        // parse jobGroup permission
    +        Map<String, String> extraInfo = MapTool.newHashMap(
    +                "jobGroups", user.getPermission()
    +        );
    +
    +        // build LoginInfo
    +        LoginInfo loginInfo = new LoginInfo(userId, user.getToken());
    +        loginInfo.setUserName(user.getUsername());
    +        loginInfo.setRoleList(roleList);
    +        loginInfo.setExtraInfo(extraInfo);
    +
    +        return Response.ofSuccess(loginInfo);
    +    }
    +
    +}
    
  • xxl-job-admin/src/main/java/com/xxl/job/admin/web/xxlsso/WebMvcConfig.java+0 25 removed
    @@ -1,25 +0,0 @@
    -package com.xxl.job.admin.web.xxlsso;
    -
    -import com.xxl.job.admin.web.interceptor.CommonDataInterceptor;
    -import jakarta.annotation.Resource;
    -import org.springframework.context.annotation.Configuration;
    -import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    -
    -/**
    - * web mvc config
    - *
    - * @author xuxueli 2018-04-02 20:48:20
    - */
    -@Configuration
    -public class WebMvcConfig implements WebMvcConfigurer {
    -
    -    @Resource
    -    private PermissionInterceptor permissionInterceptor;
    -
    -    @Override
    -    public void addInterceptors(InterceptorRegistry registry) {
    -        registry.addInterceptor(permissionInterceptor).addPathPatterns("/**");
    -    }
    -
    -}
    \ No newline at end of file
    
  • xxl-job-admin/src/main/java/com/xxl/job/admin/web/xxlsso/XxlSsoConfig.java+62 0 added
    @@ -0,0 +1,62 @@
    +package com.xxl.job.admin.web.xxlsso;
    +
    +import com.xxl.sso.core.auth.interceptor.XxlSsoWebInterceptor;
    +import com.xxl.sso.core.bootstrap.XxlSsoBootstrap;
    +import jakarta.annotation.Resource;
    +import org.springframework.beans.factory.annotation.Value;
    +import org.springframework.context.annotation.Bean;
    +import org.springframework.context.annotation.Configuration;
    +import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    +
    +/**
    + * @author xuxueli 2018-11-15
    + */
    +@Configuration
    +public class XxlSsoConfig implements WebMvcConfigurer {
    +
    +
    +    @Value("${xxl-sso.token.key}")
    +    private String tokenKey;
    +
    +    @Value("${xxl-sso.token.timeout}")
    +    private long tokenTimeout;
    +
    +    @Value("${xxl-sso.client.excluded.paths}")
    +    private String excludedPaths;
    +
    +    @Value("${xxl-sso.client.login.path}")
    +    private String loginPath;
    +
    +
    +    @Resource
    +    private SimpleLoginStore loginStore;
    +
    +
    +    /**
    +     * 1、配置 XxlSsoBootstrap
    +     */
    +    @Bean(initMethod = "start", destroyMethod = "stop")
    +    public XxlSsoBootstrap xxlSsoBootstrap() {
    +
    +        XxlSsoBootstrap bootstrap = new XxlSsoBootstrap();
    +        bootstrap.setLoginStore(loginStore);
    +        bootstrap.setTokenKey(tokenKey);
    +        bootstrap.setTokenTimeout(tokenTimeout);
    +        return bootstrap;
    +    }
    +
    +    /**
    +     * 2、配置 XxlSso 拦截器
    +     */
    +    @Override
    +    public void addInterceptors(InterceptorRegistry registry) {
    +
    +        // 2.1、build xxl-sso interceptor
    +        XxlSsoWebInterceptor webInterceptor = new XxlSsoWebInterceptor(excludedPaths, loginPath);
    +
    +        // 2.2、add interceptor
    +        registry.addInterceptor(webInterceptor).addPathPatterns("/**");
    +    }
    +
    +}
    
  • xxl-job-admin/src/main/resources/application.properties+7 1 modified
    @@ -20,7 +20,7 @@ spring.freemarker.settings.number_format=0.##########
     spring.freemarker.settings.new_builtin_class_resolver=safer
     
     ### mybatis
    -mybatis.mapper-locations=classpath:/mybatis-mapper/*Mapper.xml
    +mybatis.mapper-locations=classpath:/mapper/*Mapper.xml
     
     ### datasource-pool
     spring.datasource.type=com.zaxxer.hikari.HikariDataSource
    @@ -66,3 +66,9 @@ xxl.job.triggerpool.slow.max=100
     
     ### xxl-job, log retention days
     xxl.job.logretentiondays=30
    +
    +### xxl-sso
    +xxl-sso.token.key=xxl_job_login_token
    +xxl-sso.token.timeout=604800000
    +xxl-sso.client.excluded.paths=
    +xxl-sso.client.login.path=/auth/login
    
  • xxl-job-admin/src/main/resources/mapper/XxlJobGroupMapper.xml+0 0 renamed
  • xxl-job-admin/src/main/resources/mapper/XxlJobInfoMapper.xml+0 0 renamed
  • xxl-job-admin/src/main/resources/mapper/XxlJobLogGlueMapper.xml+70 70 renamed
    @@ -1,71 +1,71 @@
    -<?xml version="1.0" encoding="UTF-8"?>
    
    -<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
    
    -	"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    -<mapper namespace="com.xxl.job.admin.mapper.XxlJobLogGlueMapper">
    
    -	
    
    -	<resultMap id="XxlJobLogGlue" type="com.xxl.job.admin.model.XxlJobLogGlue" >
    
    -		<result column="id" property="id" />
    
    -	    <result column="job_id" property="jobId" />
    
    -		<result column="glue_type" property="glueType" />
    
    -	    <result column="glue_source" property="glueSource" />
    
    -	    <result column="glue_remark" property="glueRemark" />
    
    -	    <result column="add_time" property="addTime" />
    
    -	    <result column="update_time" property="updateTime" />
    
    -	</resultMap>
    
    -
    
    -	<sql id="Base_Column_List">
    
    -		t.id,
    
    -		t.job_id,
    
    -		t.glue_type,
    
    -		t.glue_source,
    
    -		t.glue_remark,
    
    -		t.add_time,
    
    -		t.update_time
    
    -	</sql>
    
    -	
    
    -	<insert id="save" parameterType="com.xxl.job.admin.model.XxlJobLogGlue" useGeneratedKeys="true" keyProperty="id" >
    
    -		INSERT INTO xxl_job_logglue (
    
    -			`job_id`,
    
    -			`glue_type`,
    
    -			`glue_source`,
    
    -			`glue_remark`,
    
    -			`add_time`, 
    
    -			`update_time`
    
    -		) VALUES (
    
    -			#{jobId},
    
    -			#{glueType},
    
    -			#{glueSource},
    
    -			#{glueRemark},
    
    -			#{addTime},
    
    -			#{updateTime}
    
    -		);
    
    -		<!--<selectKey resultType="java.lang.Integer" order="AFTER" keyProperty="id">
    
    -			SELECT LAST_INSERT_ID() 
    
    -		</selectKey>-->
    
    -	</insert>
    
    -	
    
    -	<select id="findByJobId" parameterType="java.lang.Integer" resultMap="XxlJobLogGlue">
    
    -		SELECT <include refid="Base_Column_List" />
    
    -		FROM xxl_job_logglue AS t
    
    -		WHERE t.job_id = #{jobId}
    
    -		ORDER BY id DESC
    
    -	</select>
    
    -	
    
    -	<delete id="removeOld" >
    
    -		DELETE FROM xxl_job_logglue
    
    -		WHERE id NOT in(
    
    -			SELECT id FROM(
    
    -				SELECT id FROM xxl_job_logglue
    
    -				WHERE `job_id` = #{jobId}
    
    -				ORDER BY update_time desc
    
    -				LIMIT 0, #{limit}
    
    -			) t1
    
    -		) AND `job_id` = #{jobId}
    
    -	</delete>
    
    -	
    
    -	<delete id="deleteByJobId" parameterType="java.lang.Integer" >
    
    -		DELETE FROM xxl_job_logglue
    
    -		WHERE `job_id` = #{jobId}
    
    -	</delete>
    
    -	
    
    +<?xml version="1.0" encoding="UTF-8"?>
    +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
    +	"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    +<mapper namespace="com.xxl.job.admin.mapper.XxlJobLogGlueMapper">
    +	
    +	<resultMap id="XxlJobLogGlue" type="com.xxl.job.admin.model.XxlJobLogGlue" >
    +		<result column="id" property="id" />
    +	    <result column="job_id" property="jobId" />
    +		<result column="glue_type" property="glueType" />
    +	    <result column="glue_source" property="glueSource" />
    +	    <result column="glue_remark" property="glueRemark" />
    +	    <result column="add_time" property="addTime" />
    +	    <result column="update_time" property="updateTime" />
    +	</resultMap>
    +
    +	<sql id="Base_Column_List">
    +		t.id,
    +		t.job_id,
    +		t.glue_type,
    +		t.glue_source,
    +		t.glue_remark,
    +		t.add_time,
    +		t.update_time
    +	</sql>
    +	
    +	<insert id="save" parameterType="com.xxl.job.admin.model.XxlJobLogGlue" useGeneratedKeys="true" keyProperty="id" >
    +		INSERT INTO xxl_job_logglue (
    +			`job_id`,
    +			`glue_type`,
    +			`glue_source`,
    +			`glue_remark`,
    +			`add_time`, 
    +			`update_time`
    +		) VALUES (
    +			#{jobId},
    +			#{glueType},
    +			#{glueSource},
    +			#{glueRemark},
    +			#{addTime},
    +			#{updateTime}
    +		);
    +		<!--<selectKey resultType="java.lang.Integer" order="AFTER" keyProperty="id">
    +			SELECT LAST_INSERT_ID() 
    +		</selectKey>-->
    +	</insert>
    +	
    +	<select id="findByJobId" parameterType="java.lang.Integer" resultMap="XxlJobLogGlue">
    +		SELECT <include refid="Base_Column_List" />
    +		FROM xxl_job_logglue AS t
    +		WHERE t.job_id = #{jobId}
    +		ORDER BY id DESC
    +	</select>
    +	
    +	<delete id="removeOld" >
    +		DELETE FROM xxl_job_logglue
    +		WHERE id NOT in(
    +			SELECT id FROM(
    +				SELECT id FROM xxl_job_logglue
    +				WHERE `job_id` = #{jobId}
    +				ORDER BY update_time desc
    +				LIMIT 0, #{limit}
    +			) t1
    +		) AND `job_id` = #{jobId}
    +	</delete>
    +	
    +	<delete id="deleteByJobId" parameterType="java.lang.Integer" >
    +		DELETE FROM xxl_job_logglue
    +		WHERE `job_id` = #{jobId}
    +	</delete>
    +	
     </mapper>
    \ No newline at end of file
    
  • xxl-job-admin/src/main/resources/mapper/XxlJobLogMapper.xml+0 0 renamed
  • xxl-job-admin/src/main/resources/mapper/XxlJobLogReportMapper.xml+0 0 renamed
  • xxl-job-admin/src/main/resources/mapper/XxlJobRegistryMapper.xml+0 0 renamed
  • xxl-job-admin/src/main/resources/mapper/XxlJobUserMapper.xml+14 0 renamed
    @@ -7,6 +7,7 @@
     		<result column="id" property="id" />
     		<result column="username" property="username" />
     	    <result column="password" property="password" />
    +		<result column="token" property="token" />
     	    <result column="role" property="role" />
     	    <result column="permission" property="permission" />
     	</resultMap>
    @@ -15,6 +16,7 @@
     		t.id,
     		t.username,
     		t.password,
    +		t.token,
     		t.role,
     		t.permission
     	</sql>
    @@ -53,6 +55,12 @@
     		WHERE t.username = #{username}
     	</select>
     
    +	<select id="loadById" parameterType="java.util.HashMap" resultMap="XxlJobUser">
    +		SELECT <include refid="Base_Column_List" />
    +		FROM xxl_job_user AS t
    +		WHERE t.id = #{id}
    +	</select>
    +
     	<insert id="save" parameterType="com.xxl.job.admin.model.XxlJobUser" useGeneratedKeys="true" keyProperty="id" >
     		INSERT INTO xxl_job_user (
     			username,
    @@ -84,4 +92,10 @@
     		WHERE id = #{id}
     	</delete>
     
    +	<update id="updateToken" parameterType="java.util.HashMap" >
    +		UPDATE xxl_job_user
    +		SET token = #{token}
    +		WHERE id = #{id}
    +	</update>
    +
     </mapper>
    \ No newline at end of file
    
  • xxl-job-admin/src/main/resources/static/js/login.1.js+1 1 modified
    @@ -46,7 +46,7 @@ $(function(){
                 element.parent('div').append(error);  
             },
             submitHandler : function(form) {
    -			$.post(base_url + "/auth/login", $("#loginForm").serialize(), function(data, status) {
    +			$.post(base_url + "/auth/doLogin", $("#loginForm").serialize(), function(data, status) {
     				if (data.code == "200") {
                         layer.msg( I18n.login_success );
                         setTimeout(function(){
    
  • xxl-job-admin/src/main/resources/templates/common/common.macro.ftl+3 3 modified
    @@ -83,8 +83,8 @@
     				<ul class="nav navbar-nav">
     					<#-- login user -->
                         <li class="dropdown">
    -                        <a href="javascript:" class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
    -                            ${I18n.system_welcome} ${loginUser.username!}
    +                        <a href="javascript:" class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false" style="font-weight: bold;">
    +                            ${I18n.system_welcome} ${xxl_sso_user.userName!}
                                 <span class="caret"></span>
                             </a>
                             <ul class="dropdown-menu" role="menu">
    @@ -141,7 +141,7 @@
                     <li class="nav-click <#if pageName == "index">active</#if>" ><a href="${request.contextPath}/"><i class="fa fa-circle-o text-aqua"></i><span>${I18n.job_dashboard_name}</span></a></li>
     				<li class="nav-click <#if pageName == "jobinfo">active</#if>" ><a href="${request.contextPath}/jobinfo"><i class="fa fa-circle-o text-yellow"></i><span>${I18n.jobinfo_name}</span></a></li>
     				<li class="nav-click <#if pageName == "joblog">active</#if>" ><a href="${request.contextPath}/joblog"><i class="fa fa-circle-o text-green"></i><span>${I18n.joblog_name}</span></a></li>
    -				<#if loginUser.role == 1>
    +				<#if xxl_sso_user.roleList?? && xxl_sso_user.roleList?seq_contains("ADMIN") >
                         <li class="nav-click <#if pageName == "jobgroup">active</#if>" ><a href="${request.contextPath}/jobgroup"><i class="fa fa-circle-o text-red"></i><span>${I18n.jobgroup_name}</span></a></li>
                         <li class="nav-click <#if pageName == "user">active</#if>" ><a href="${request.contextPath}/user"><i class="fa fa-circle-o text-purple"></i><span>${I18n.user_manage}</span></a></li>
     				</#if>
    
  • xxl-job-admin/src/main/resources/templates/joblog/joblog.index.ftl+1 1 modified
    @@ -30,7 +30,7 @@
      					<div class="input-group">
     	                	<span class="input-group-addon">${I18n.jobinfo_field_jobgroup}</span>
                     		<select class="form-control" id="jobGroup"  paramVal="<#if jobInfo?exists>${jobInfo.jobGroup}</#if>" >
    -                            <#if loginUser.role == 1>
    +                            <#if xxl_sso_user.roleList?? && xxl_sso_user.roleList?seq_contains("ADMIN") >
                                     <option value="0" >${I18n.system_all}</option>  <#-- 仅管理员支持查询全部;普通用户仅支持查询有权限的 jobGroup -->
                                 </#if>
                     			<#list JobGroupList as group>
    
  • xxl-job-admin/src/test/java/com/xxl/job/admin/controller/JobInfoControllerTest.java+3 3 modified
    @@ -1,6 +1,6 @@
     package com.xxl.job.admin.controller;
     
    -import com.xxl.job.admin.service.impl.LoginService;
    +import com.xxl.sso.core.constant.Const;
     import jakarta.servlet.http.Cookie;
     import org.junit.jupiter.api.BeforeEach;
     import org.junit.jupiter.api.Test;
    @@ -21,12 +21,12 @@ public class JobInfoControllerTest extends AbstractSpringMvcTest {
       @BeforeEach
       public void login() throws Exception {
         MvcResult ret = mockMvc.perform(
    -        post("/auth/login")
    +        post("/auth/doLogin")
                 .contentType(MediaType.APPLICATION_FORM_URLENCODED)
                 .param("userName", "admin")
                 .param("password", "123456")
         ).andReturn();
    -    cookie = ret.getResponse().getCookie(LoginService.LOGIN_IDENTITY_KEY);
    +    cookie = ret.getResponse().getCookie(Const.XXL_SSO_TOKEN);
       }
     
       @Test
    
  • xxl-job-core/src/main/java/com/xxl/job/core/util/GsonTool.java+125 11 modified
    @@ -2,25 +2,32 @@
     
     import com.google.gson.Gson;
     import com.google.gson.GsonBuilder;
    +import com.google.gson.JsonElement;
     import com.google.gson.reflect.TypeToken;
     
    -import java.lang.reflect.ParameterizedType;
     import java.lang.reflect.Type;
    -import java.util.List;
    +import java.util.ArrayList;
    +import java.util.HashMap;
     
     /**
    + * gson tool (From https://github.com/xuxueli/xxl-tool )
    + *
      * @author xuxueli 2020-04-11 20:56:31
      */
     public class GsonTool {
     
         private static Gson gson = null;
         static {
    -            gson= new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
    +        gson= new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").disableHtmlEscaping().create();
         }
     
         /**
          * Object 转成 json
          *
    +     * <pre>
    +     *     String json = GsonTool.toJson(new Demo());
    +     * </pre>
    +     *
          * @param src
          * @return String
          */
    @@ -31,6 +38,10 @@ public static String toJson(Object src) {
         /**
          * json 转成 特定的cls的Object
          *
    +     * <pre>
    +     *     Demo demo = GsonTool.fromJson(json, Demo.class);
    +     * </pre>
    +     *
          * @param json
          * @param classOfT
          * @return
    @@ -42,12 +53,16 @@ public static <T> T fromJson(String json, Class<T> classOfT) {
         /**
          * json 转成 特定的 rawClass<classOfT> 的Object
          *
    +     * <pre>
    +     *     Response<Demo> response = GsonTool.fromJson(json, Response.class, Demo.class);
    +     * </pre>
    +     *
          * @param json
          * @param classOfT
          * @param argClassOfT
          * @return
          */
    -    public static <T> T fromJson(String json, Class<T> classOfT, Class argClassOfT) {
    +    /*public static <T> T fromJson(String json, Class<T> classOfT, Class argClassOfT) {
             Type type = new ParameterizedType4ReturnT(classOfT, new Class[]{argClassOfT});
             return gson.fromJson(json, type);
         }
    @@ -68,21 +83,120 @@ public Type getRawType() {
             }
             @Override
             public Type getOwnerType() {return null;}
    +    }*/
    +
    +    /**
    +     * json 转成 特定的 Type 的Object
    +     *
    +     * @param json
    +     * @param typeOfT
    +     * @return
    +     * @param <T>
    +     */
    +    public static <T> T  fromJson(String json, Type typeOfT) {
    +        return gson.fromJson(json, typeOfT);
    +    }
    +
    +    /**
    +     * json 转成 特定的 Type 的Object
    +     *
    +     * <pre>
    +     *     Response<Demo> response = GsonTool.fromJson(json, Response.class, Demo.class);
    +     * </pre>
    +     *
    +     * @param json
    +     * @param rawType
    +     * @param typeArguments
    +     * @return
    +     */
    +    public static <T> T  fromJson(String json, Type rawType, Type... typeArguments) {
    +        Type type = TypeToken.getParameterized(rawType, typeArguments).getType();
    +        return gson.fromJson(json, type);
    +    }
    +
    +    /**
    +     * json 转成 特定的cls的 ArrayList
    +     *
    +     * <pre>
    +     *     List<Demo> demoList = GsonTool.fromJsonList(json, Demo.class);
    +     * </pre>
    +     *
    +     * @param json
    +     * @param classOfT
    +     * @return
    +     */
    +    public static <T> ArrayList<T> fromJsonList(String json, Class<T> classOfT) {
    +        Type type = TypeToken.getParameterized(ArrayList.class, classOfT).getType();
    +        return gson.fromJson(json, type);
    +    }
    +
    +    /**
    +     * json 转成 特定的cls的 HashMap
    +     *
    +     * <pre>
    +     *     HashMap<String, Demo> map = GsonTool.fromJsonMap(json, String.class, Demo.class);
    +     * </pre>
    +     *
    +     * @param json
    +     * @param keyClass
    +     * @param valueClass
    +     * @return
    +     * @param <K>
    +     * @param <V>
    +     */
    +    public static <K, V> HashMap<K, V> fromJsonMap(String json, Class<K> keyClass, Class<V> valueClass) {
    +        Type type = TypeToken.getParameterized(HashMap.class, keyClass, valueClass).getType();
    +        return gson.fromJson(json, type);
    +    }
    +
    +    // ---------------------------------
    +
    +    /**
    +     * Object 转成 JsonElement
    +     *
    +     * @param src
    +     * @return
    +     */
    +    public static JsonElement toJsonElement(Object src) {
    +        return gson.toJsonTree(src);
         }
     
         /**
    -     * json 转成 特定的cls的list
    +     * JsonElement 转成 特定的cls的Object
          *
          * @param json
          * @param classOfT
          * @return
    +     * @param <T>
    +     */
    +    public static <T> T fromJsonElement(JsonElement json, Class<T> classOfT) {
    +        return gson.fromJson(json, classOfT);
    +    }
    +
    +    /**
    +     * JsonElement 转成 特定的 rawClass<classOfT> 的Object
    +     *
    +     * @param json
    +     * @param typeOfT
    +     * @return
    +     * @param <T>
    +     */
    +    public static <T> T fromJsonElement(JsonElement json, Type typeOfT) {
    +        return gson.fromJson(json, typeOfT);
    +    }
    +
    +    /**
    +     * JsonElement 转成 特定的 Type 的 Object
    +     *
    +     * @param json
    +     * @param rawType
    +     * @param typeArguments
    +     * @return
    +     * @param <T>
          */
    -    public static <T> List<T> fromJsonList(String json, Class<T> classOfT) {
    -        return gson.fromJson(
    -                json,
    -                new TypeToken<List<T>>() {
    -                }.getType()
    -        );
    +    public static <T> T fromJsonElement(JsonElement json, Type rawType, Type... typeArguments) {
    +        Type typeOfT = TypeToken.getParameterized(rawType, typeArguments).getType();
    +        return gson.fromJson(json, typeOfT);
         }
     
     }
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

7

News mentions

0

No linked articles in our index yet.