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

3.2.0-release
xuxueli 4 weeks ago
parent e02f2c65c0
commit cb1bd548a6

@ -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[规划中]

@ -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;
}

@ -0,0 +1,7 @@
package com.xxl.job.admin.constant;
public class Consts {
public static final String ADMIN_ROLE = "ADMIN";
}

@ -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

@ -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 class JobCodeController {
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,8 +73,8 @@ public class JobCodeController {
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);

@ -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.XxlJobInfoMapper;
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 class JobGroupController {
@RequestMapping("/save")
@ResponseBody
@PermissionLimit(adminuser = true)
@XxlSso(role = Consts.ADMIN_ROLE)
public ReturnT<String> save(XxlJobGroup xxlJobGroup){
// valid
@ -107,7 +108,7 @@ public class JobGroupController {
@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 @@ public class JobGroupController {
@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 class JobGroupController {
@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();

@ -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.RequestMapping;
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 class JobInfoController {
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 class JobInfoController {
@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 class JobInfoController {
@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")
@ -161,4 +166,50 @@ public class JobInfoController {
}
// -------------------- 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();
}
}
}

@ -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 class JobLogController {
model.addAttribute("jobInfo", jobInfo);
// valid permission
PermissionInterceptor.validJobGroupPermission(request, jobInfo.getJobGroup());
JobInfoController.validJobGroupPermission(request, jobInfo.getJobGroup());
}
return "joblog/joblog.index";
@ -97,8 +96,8 @@ public class JobLogController {
@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;
@ -133,7 +132,7 @@ public class JobLogController {
}
// valid permission
PermissionInterceptor.validJobGroupPermission(request, jobLog.getJobGroup());
JobInfoController.validJobGroupPermission(request, jobLog.getJobGroup());
// data
model.addAttribute("triggerCode", jobLog.getTriggerCode());
@ -249,7 +248,7 @@ public class JobLogController {
@RequestParam("jobId") int jobId,
@RequestParam("type") int type){
// valid permission
PermissionInterceptor.validJobGroupPermission(request, jobGroup);
JobInfoController.validJobGroupPermission(request, jobGroup);
// opt
Date clearBeforeTime = null;

@ -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 class JobUserController {
@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 class JobUserController {
@RequestMapping("/add")
@ResponseBody
@PermissionLimit(adminuser = true)
@XxlSso(role = Consts.ADMIN_ROLE)
public ReturnT<String> add(XxlJobUser xxlJobUser) {
// valid username
@ -110,12 +113,12 @@ public class JobUserController {
@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 class JobUserController {
@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 class JobUserController {
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"));
}

@ -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 @@ import org.springframework.web.servlet.view.RedirectView;
@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,
@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){
boolean ifRem = (ifRemember!=null && ifRemember.trim().length()>0 && "on".equals(ifRemember))?true:false;
return loginService.login(request, response, userName, password, ifRem);
// 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());
}
}

@ -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 interface XxlJobUserMapper {
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);
}

@ -10,6 +10,7 @@ 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列表多个逗号分割
@ -37,6 +38,14 @@ public class XxlJobUser {
this.password = password;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public int getRole() {
return role;
}

@ -4,6 +4,7 @@ package com.xxl.job.admin.service;
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,7 +35,7 @@ public interface XxlJobService {
* @param jobInfo
* @return
*/
public ReturnT<String> add(XxlJobInfo jobInfo, XxlJobUser loginUser);
public ReturnT<String> add(XxlJobInfo jobInfo, LoginInfo loginInfo);
/**
* update job
@ -42,7 +43,7 @@ public interface XxlJobService {
* @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

@ -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;
}
}

@ -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 class XxlJobServiceImpl implements XxlJobService {
}
@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 class XxlJobServiceImpl implements XxlJobService {
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 @@ public class XxlJobServiceImpl implements XxlJobService {
}
@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 class XxlJobServiceImpl implements XxlJobService {
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 class XxlJobServiceImpl implements XxlJobService {
@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 class XxlJobServiceImpl implements XxlJobService {
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() {

@ -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 class I18nUtil {
return GsonTool.toJson(map);
}
}

@ -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;

@ -5,6 +5,7 @@ import com.xxl.tool.freemarker.FtlTool;
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 @@ import java.util.HashMap;
*
* @author xuxueli 2015-12-12 18:09:04
*/
@Component
@Configuration
public class CommonDataInterceptor implements WebMvcConfigurer {
@Override

@ -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;
}
}

@ -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
*
* 1store by database
* 2If 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);
}
}

@ -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("/**");
}
}

@ -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("/**");
}
}

@ -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

@ -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>

@ -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(){

@ -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>

@ -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>

@ -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

@ -2,25 +2,32 @@ package com.xxl.job.core.util;
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 class GsonTool {
/**
* json clsObject
*
* <pre>
* Demo demo = GsonTool.fromJson(json, Demo.class);
* </pre>
*
* @param json
* @param classOfT
* @return
@ -42,12 +53,16 @@ public class GsonTool {
/**
* 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 class GsonTool {
}
@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 clslist
* 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> List<T> fromJsonList(String json, Class<T> classOfT) {
return gson.fromJson(
json,
new TypeToken<List<T>>() {
}.getType()
);
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);
}
/**
* JsonElement clsObject
*
* @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> T fromJsonElement(JsonElement json, Type rawType, Type... typeArguments) {
Type typeOfT = TypeToken.getParameterized(rawType, typeArguments).getType();
return gson.fromJson(json, typeOfT);
}
}

Loading…
Cancel
Save