mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2024-11-22 23:31:52 +08:00
将 LoginUser 重构到 UserSessionService 模块汇总
This commit is contained in:
parent
b557251b6f
commit
ab94fe2d4b
7
pom.xml
7
pom.xml
@ -53,7 +53,6 @@
|
|||||||
<!-- 工具类相关 -->
|
<!-- 工具类相关 -->
|
||||||
<lombok.version>1.16.14</lombok.version>
|
<lombok.version>1.16.14</lombok.version>
|
||||||
<mapstruct.version>1.4.1.Final</mapstruct.version>
|
<mapstruct.version>1.4.1.Final</mapstruct.version>
|
||||||
<jjwt.version>0.9.1</jjwt.version>
|
|
||||||
<hutool.version>5.5.6</hutool.version>
|
<hutool.version>5.5.6</hutool.version>
|
||||||
<easyexcel.verion>2.2.7</easyexcel.verion>
|
<easyexcel.verion>2.2.7</easyexcel.verion>
|
||||||
</properties>
|
</properties>
|
||||||
@ -177,12 +176,6 @@
|
|||||||
<version>${lombok.version}</version>
|
<version>${lombok.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
|
||||||
<artifactId>jjwt</artifactId>
|
|
||||||
<version>${jjwt.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.projectlombok</groupId>
|
<groupId>org.projectlombok</groupId>
|
||||||
<artifactId>lombok</artifactId>
|
<artifactId>lombok</artifactId>
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
package com.ruoyi;
|
|
||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|
||||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 启动程序
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
|
|
||||||
public class RuoYiApplication
|
|
||||||
{
|
|
||||||
public static void main(String[] args)
|
|
||||||
{
|
|
||||||
// System.setProperty("spring.devtools.restart.enabled", "false");
|
|
||||||
SpringApplication.run(RuoYiApplication.class, args);
|
|
||||||
System.out.println("(♥◠‿◠)ノ゙ 若依启动成功 ლ(´ڡ`ლ)゙ \n" +
|
|
||||||
" .-------. ____ __ \n" +
|
|
||||||
" | _ _ \\ \\ \\ / / \n" +
|
|
||||||
" | ( ' ) | \\ _. / ' \n" +
|
|
||||||
" |(_ o _) / _( )_ .' \n" +
|
|
||||||
" | (_,_).' __ ___(_ o _)' \n" +
|
|
||||||
" | |\\ \\ | || |(_,_)' \n" +
|
|
||||||
" | | \\ `' /| `-' / \n" +
|
|
||||||
" | | \\ / \\ / \n" +
|
|
||||||
" ''-' `'-' `-..-' ");
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,92 +0,0 @@
|
|||||||
package com.ruoyi.web.controller.monitor;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
import com.ruoyi.common.annotation.Log;
|
|
||||||
import com.ruoyi.common.constant.Constants;
|
|
||||||
import com.ruoyi.common.core.controller.BaseController;
|
|
||||||
import com.ruoyi.common.core.domain.AjaxResult;
|
|
||||||
import com.ruoyi.common.core.domain.model.LoginUser;
|
|
||||||
import com.ruoyi.common.core.page.TableDataInfo;
|
|
||||||
import com.ruoyi.common.core.redis.RedisCache;
|
|
||||||
import com.ruoyi.common.enums.BusinessType;
|
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
|
||||||
import com.ruoyi.system.domain.SysUserOnline;
|
|
||||||
import com.ruoyi.system.service.ISysUserOnlineService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 在线用户监控
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/monitor/online")
|
|
||||||
public class SysUserOnlineController extends BaseController
|
|
||||||
{
|
|
||||||
@Autowired
|
|
||||||
private ISysUserOnlineService userOnlineService;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private RedisCache redisCache;
|
|
||||||
|
|
||||||
@PreAuthorize("@ss.hasPermi('monitor:online:list')")
|
|
||||||
@GetMapping("/list")
|
|
||||||
public TableDataInfo list(String ipaddr, String userName)
|
|
||||||
{
|
|
||||||
Collection<String> keys = redisCache.keys(Constants.LOGIN_TOKEN_KEY + "*");
|
|
||||||
List<SysUserOnline> userOnlineList = new ArrayList<SysUserOnline>();
|
|
||||||
for (String key : keys)
|
|
||||||
{
|
|
||||||
LoginUser user = redisCache.getCacheObject(key);
|
|
||||||
if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName))
|
|
||||||
{
|
|
||||||
if (StringUtils.equals(ipaddr, user.getIpaddr()) && StringUtils.equals(userName, user.getUsername()))
|
|
||||||
{
|
|
||||||
userOnlineList.add(userOnlineService.selectOnlineByInfo(ipaddr, userName, user));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (StringUtils.isNotEmpty(ipaddr))
|
|
||||||
{
|
|
||||||
if (StringUtils.equals(ipaddr, user.getIpaddr()))
|
|
||||||
{
|
|
||||||
userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr, user));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (StringUtils.isNotEmpty(userName) && StringUtils.isNotNull(user.getUser()))
|
|
||||||
{
|
|
||||||
if (StringUtils.equals(userName, user.getUsername()))
|
|
||||||
{
|
|
||||||
userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
userOnlineList.add(userOnlineService.loginUserToUserOnline(user));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Collections.reverse(userOnlineList);
|
|
||||||
userOnlineList.removeAll(Collections.singleton(null));
|
|
||||||
return getDataTable(userOnlineList);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 强退用户
|
|
||||||
*/
|
|
||||||
@PreAuthorize("@ss.hasPermi('monitor:online:forceLogout')")
|
|
||||||
@Log(title = "在线用户", businessType = BusinessType.FORCE)
|
|
||||||
@DeleteMapping("/{tokenId}")
|
|
||||||
public AjaxResult forceLogout(@PathVariable String tokenId)
|
|
||||||
{
|
|
||||||
redisCache.deleteObject(Constants.LOGIN_TOKEN_KEY + tokenId);
|
|
||||||
return AjaxResult.success();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
restart.include.json=/com.alibaba.fastjson.*.jar
|
|
@ -34,20 +34,6 @@ logging:
|
|||||||
com.ruoyi: debug
|
com.ruoyi: debug
|
||||||
org.springframework: warn
|
org.springframework: warn
|
||||||
|
|
||||||
# Spring配置
|
|
||||||
spring:
|
|
||||||
# 资源信息
|
|
||||||
messages:
|
|
||||||
# 国际化资源文件路径
|
|
||||||
basename: i18n/messages
|
|
||||||
profiles:
|
|
||||||
active: druid
|
|
||||||
# 服务模块
|
|
||||||
devtools:
|
|
||||||
restart:
|
|
||||||
# 热部署开关
|
|
||||||
enabled: true
|
|
||||||
|
|
||||||
# 防止XSS攻击
|
# 防止XSS攻击
|
||||||
xss:
|
xss:
|
||||||
# 过滤开关
|
# 过滤开关
|
||||||
|
@ -34,7 +34,4 @@ public class BaseDO implements Serializable {
|
|||||||
@TableLogic
|
@TableLogic
|
||||||
private Integer deleted;
|
private Integer deleted;
|
||||||
|
|
||||||
// /** 备注 */ TODO 思考下,怎么解决
|
|
||||||
// private String remark;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,8 @@ import java.util.List;
|
|||||||
import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
|
import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
|
||||||
import static cn.iocoder.dashboard.framework.security.core.util.SecurityUtils.getLoginUserId;
|
import static cn.iocoder.dashboard.framework.security.core.util.SecurityUtils.getLoginUserId;
|
||||||
import static cn.iocoder.dashboard.framework.security.core.util.SecurityUtils.getLoginUserRoleIds;
|
import static cn.iocoder.dashboard.framework.security.core.util.SecurityUtils.getLoginUserRoleIds;
|
||||||
|
import static cn.iocoder.dashboard.util.servlet.ServletUtils.getClientIP;
|
||||||
|
import static cn.iocoder.dashboard.util.servlet.ServletUtils.getUserAgent;
|
||||||
|
|
||||||
@Api("认证 API")
|
@Api("认证 API")
|
||||||
@RestController
|
@RestController
|
||||||
@ -47,7 +49,7 @@ public class SysAuthController {
|
|||||||
@PostMapping("/login")
|
@PostMapping("/login")
|
||||||
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
|
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
|
||||||
public CommonResult<SysAuthLoginRespVO> login(@RequestBody @Valid SysAuthLoginReqVO reqVO) {
|
public CommonResult<SysAuthLoginRespVO> login(@RequestBody @Valid SysAuthLoginReqVO reqVO) {
|
||||||
String token = authService.login(reqVO.getUsername(), reqVO.getPassword(), reqVO.getUuid(), reqVO.getCode());
|
String token = authService.login(reqVO, getClientIP(), getUserAgent());
|
||||||
// 返回结果
|
// 返回结果
|
||||||
return success(SysAuthLoginRespVO.builder().token(token).build());
|
return success(SysAuthLoginRespVO.builder().token(token).build());
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,49 @@
|
|||||||
|
package cn.iocoder.dashboard.modules.system.controller.auth;
|
||||||
|
|
||||||
|
import cn.iocoder.dashboard.common.pojo.CommonResult;
|
||||||
|
import cn.iocoder.dashboard.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.dashboard.modules.system.controller.auth.vo.session.SysUserSessionPageItemRespVO;
|
||||||
|
import cn.iocoder.dashboard.modules.system.controller.auth.vo.session.SysUserSessionPageReqVO;
|
||||||
|
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.auth.SysUserSessionDO;
|
||||||
|
import cn.iocoder.dashboard.modules.system.service.auth.SysUserSessionService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiImplicitParam;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
|
||||||
|
|
||||||
|
@Api("用户 Session API")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/user-session")
|
||||||
|
public class SysUserSessionController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SysUserSessionService userSessionService;
|
||||||
|
|
||||||
|
@ApiOperation("获得 Session 分页列表")
|
||||||
|
@PreAuthorize("@ss.hasPermission('system:user-session:page')")
|
||||||
|
@GetMapping("/page")
|
||||||
|
public CommonResult<PageResult<SysUserSessionPageItemRespVO>> getUserSessionPage(@Validated SysUserSessionPageReqVO reqVO) {
|
||||||
|
// 获得 Session 分页
|
||||||
|
PageResult<SysUserSessionDO> sessionPage = userSessionService.getUserSessionPage(reqVO);
|
||||||
|
|
||||||
|
//
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("删除 Session")
|
||||||
|
@PreAuthorize("@ss.hasPermission('system:user-session:delete')")
|
||||||
|
@DeleteMapping("/delete")
|
||||||
|
@ApiImplicitParam(name = "id", value = "Session 编号", required = true, dataTypeClass = String.class,
|
||||||
|
example = "fe50b9f6-d177-44b1-8da9-72ea34f63db7")
|
||||||
|
public CommonResult<Boolean> delete(@RequestParam("id") String id) {
|
||||||
|
userSessionService.deleteUserSession(id);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
package cn.iocoder.dashboard.modules.system.controller.auth.vo.session;
|
||||||
|
|
||||||
|
import cn.iocoder.dashboard.common.pojo.PageParam;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@ApiModel(value = "用户在线 Session Response VO", description = "相比用户基本信息来说,会多部门、用户账号等信息")
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class SysUserSessionPageItemRespVO extends PageParam {
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "Session 编号", required = true, example = "fe50b9f6-d177-44b1-8da9-72ea34f63db7")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "用户 IP", required = true, example = "127.0.0.1")
|
||||||
|
private String userIp;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "浏览器 UserAgent", required = true, example = "Mozilla/5.0")
|
||||||
|
private String userAgent;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "登陆时间", required = true)
|
||||||
|
private String createTime;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "用户账号", required = true, example = "yudao")
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "部门名称", example = "研发部")
|
||||||
|
private String deptName;
|
||||||
|
|
||||||
|
}
|
@ -2,11 +2,22 @@ package cn.iocoder.dashboard.modules.system.controller.auth.vo.session;
|
|||||||
|
|
||||||
import cn.iocoder.dashboard.common.pojo.PageParam;
|
import cn.iocoder.dashboard.common.pojo.PageParam;
|
||||||
import io.swagger.annotations.ApiModel;
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
|
||||||
@ApiModel("在线用户 Session 分页 Request VO")
|
@ApiModel("在线用户 Session 分页 Request VO")
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class SysUserSessionPageReqVO extends PageParam {
|
public class SysUserSessionPageReqVO extends PageParam {
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "用户 IP", example = "127.0.0.1", notes = "模糊匹配")
|
||||||
|
@NotEmpty(message = "用户 IP 不能为空")
|
||||||
|
private String userIp;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "用户账号", example = "yudao", notes = "模糊匹配")
|
||||||
|
private String username;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@ package cn.iocoder.dashboard.modules.system.dal.mysql.dao.auth;
|
|||||||
|
|
||||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.auth.SysUserSessionDO;
|
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.auth.SysUserSessionDO;
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
public interface SysUserOnlineMapper extends BaseMapper<SysUserSessionDO> {
|
@Mapper
|
||||||
|
public interface SysUserSessionMapper extends BaseMapper<SysUserSessionDO> {
|
||||||
}
|
}
|
@ -1,17 +1,26 @@
|
|||||||
package cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.auth;
|
package cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.auth;
|
||||||
|
|
||||||
import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO;
|
import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO;
|
||||||
|
import cn.iocoder.dashboard.framework.security.core.LoginUser;
|
||||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO;
|
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 在线用户表
|
* 在线用户表
|
||||||
|
*
|
||||||
|
* 我们已经将 {@link LoginUser} 缓存在 Redis 当中。
|
||||||
|
* 这里额外存储在线用户到 MySQL 中,目的是为了方便管理界面可以灵活查询。
|
||||||
|
* 同时,通过定时轮询 SysUserSessionDO 表,可以主动删除 Redis 的缓存,因为 Redis 的过期删除是延迟的。
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@TableName(value = "sys_user_session", autoResultMap = true)
|
@TableName(value = "sys_user_session", autoResultMap = true)
|
||||||
@Data
|
@Data
|
||||||
|
@Builder
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class SysUserSessionDO extends BaseDO {
|
public class SysUserSessionDO extends BaseDO {
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package cn.iocoder.dashboard.modules.system.service.auth;
|
package cn.iocoder.dashboard.modules.system.service.auth;
|
||||||
|
|
||||||
import cn.iocoder.dashboard.framework.security.core.service.SecurityAuthFrameworkService;
|
import cn.iocoder.dashboard.framework.security.core.service.SecurityAuthFrameworkService;
|
||||||
|
import cn.iocoder.dashboard.modules.system.controller.auth.vo.auth.SysAuthLoginReqVO;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 认证 Service 接口
|
* 认证 Service 接口
|
||||||
@ -11,6 +12,14 @@ import cn.iocoder.dashboard.framework.security.core.service.SecurityAuthFramewor
|
|||||||
*/
|
*/
|
||||||
public interface SysAuthService extends SecurityAuthFrameworkService {
|
public interface SysAuthService extends SecurityAuthFrameworkService {
|
||||||
|
|
||||||
String login(String username, String password, String captchaUUID, String captchaCode);
|
/**
|
||||||
|
* 登陆用户
|
||||||
|
*
|
||||||
|
* @param reqVO 登陆信息
|
||||||
|
* @param userIp 用户 IP
|
||||||
|
* @param userAgent 用户 UA
|
||||||
|
* @return 身份令牌,使用 JWT 方式
|
||||||
|
*/
|
||||||
|
String login(SysAuthLoginReqVO reqVO, String userIp, String userAgent);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
package cn.iocoder.dashboard.modules.system.service.auth;
|
|
||||||
|
|
||||||
import io.jsonwebtoken.Claims;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Token Service 接口
|
|
||||||
*
|
|
||||||
* 提供访问 Token 令牌,目前基于 JWT 实现
|
|
||||||
*/
|
|
||||||
public interface SysTokenService {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建 Token
|
|
||||||
*
|
|
||||||
* @param subject 主体
|
|
||||||
* @return Token 字符串
|
|
||||||
*/
|
|
||||||
String createToken(String subject);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 解析 Token,返回 claims 数据声明
|
|
||||||
*
|
|
||||||
* @param token Token
|
|
||||||
* @return claims
|
|
||||||
*/
|
|
||||||
Claims parseToken(String token);
|
|
||||||
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
package cn.iocoder.dashboard.modules.system.service.auth;
|
|
||||||
|
|
||||||
import cn.iocoder.dashboard.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.dashboard.modules.system.controller.auth.vo.session.SysUserSessionPageReqVO;
|
|
||||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.auth.SysUserSessionDO;
|
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 在线用户 Session Service 接口
|
|
||||||
*/
|
|
||||||
public interface SysUserOnlineService {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建在线用户 Session
|
|
||||||
*
|
|
||||||
* @param sessionId Session 编号
|
|
||||||
* @param userId 用户编号
|
|
||||||
* @param userIp 用户 IP
|
|
||||||
* @param userAgent 用户 UA
|
|
||||||
*/
|
|
||||||
void createUserOnline(String sessionId, Long userId, String userIp, String userAgent);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新在线用户 Session 的更新时间
|
|
||||||
*
|
|
||||||
* @param sessionId Session 编号
|
|
||||||
* @param updateTime 更新时间
|
|
||||||
*/
|
|
||||||
void updateUserOnlineUpdateTime(String sessionId, Date updateTime);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得在线用户分页列表
|
|
||||||
*
|
|
||||||
* @param reqVO 分页条件
|
|
||||||
* @return 份额与列表
|
|
||||||
*/
|
|
||||||
PageResult<SysUserSessionDO> getUserSessionPage(SysUserSessionPageReqVO reqVO);
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,63 @@
|
|||||||
|
package cn.iocoder.dashboard.modules.system.service.auth;
|
||||||
|
|
||||||
|
import cn.iocoder.dashboard.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.dashboard.framework.security.core.LoginUser;
|
||||||
|
import cn.iocoder.dashboard.modules.system.controller.auth.vo.session.SysUserSessionPageReqVO;
|
||||||
|
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.auth.SysUserSessionDO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在线用户 Session Service 接口
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public interface SysUserSessionService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建在线用户 Session
|
||||||
|
*
|
||||||
|
* @param loginUser 登陆用户
|
||||||
|
* @param userIp 用户 IP
|
||||||
|
* @param userAgent 用户 UA
|
||||||
|
* @return Session 编号
|
||||||
|
*/
|
||||||
|
String createUserSession(LoginUser loginUser, String userIp, String userAgent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新在线用户 Session 的更新时间
|
||||||
|
*
|
||||||
|
* @param sessionId Session 编号
|
||||||
|
* @param loginUser 登陆用户
|
||||||
|
*/
|
||||||
|
void refreshUserSession(String sessionId, LoginUser loginUser);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除在线用户 Session
|
||||||
|
*
|
||||||
|
* @param sessionId Session 编号
|
||||||
|
*/
|
||||||
|
void deleteUserSession(String sessionId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得 Session 编号对应的在线用户
|
||||||
|
*
|
||||||
|
* @param sessionId Session 编号
|
||||||
|
* @return 在线用户
|
||||||
|
*/
|
||||||
|
LoginUser getLoginUser(String sessionId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得 Session 超时时间,单位:毫秒
|
||||||
|
*
|
||||||
|
* @return 超时时间
|
||||||
|
*/
|
||||||
|
Long getSessionTimeoutMillis();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得在线用户分页列表
|
||||||
|
*
|
||||||
|
* @param reqVO 分页条件
|
||||||
|
* @return 份额与列表
|
||||||
|
*/
|
||||||
|
PageResult<SysUserSessionDO> getUserSessionPage(SysUserSessionPageReqVO reqVO);
|
||||||
|
|
||||||
|
}
|
@ -1,28 +1,22 @@
|
|||||||
package cn.iocoder.dashboard.modules.system.service.auth.impl;
|
package cn.iocoder.dashboard.modules.system.service.auth.impl;
|
||||||
|
|
||||||
import cn.hutool.core.util.IdUtil;
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
|
import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
|
||||||
import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil;
|
import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil;
|
||||||
import cn.iocoder.dashboard.framework.security.config.SecurityProperties;
|
|
||||||
import cn.iocoder.dashboard.framework.security.core.LoginUser;
|
import cn.iocoder.dashboard.framework.security.core.LoginUser;
|
||||||
import cn.iocoder.dashboard.framework.tracer.core.util.TracerUtils;
|
import cn.iocoder.dashboard.framework.tracer.core.util.TracerUtils;
|
||||||
|
import cn.iocoder.dashboard.modules.system.controller.auth.vo.auth.SysAuthLoginReqVO;
|
||||||
import cn.iocoder.dashboard.modules.system.controller.logger.vo.loginlog.SysLoginLogCreateReqVO;
|
import cn.iocoder.dashboard.modules.system.controller.logger.vo.loginlog.SysLoginLogCreateReqVO;
|
||||||
import cn.iocoder.dashboard.modules.system.convert.auth.SysAuthConvert;
|
import cn.iocoder.dashboard.modules.system.convert.auth.SysAuthConvert;
|
||||||
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO;
|
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO;
|
||||||
import cn.iocoder.dashboard.modules.system.dal.redis.dao.auth.SysLoginUserRedisDAO;
|
|
||||||
import cn.iocoder.dashboard.modules.system.enums.logger.SysLoginLogTypeEnum;
|
import cn.iocoder.dashboard.modules.system.enums.logger.SysLoginLogTypeEnum;
|
||||||
import cn.iocoder.dashboard.modules.system.enums.logger.SysLoginResultEnum;
|
import cn.iocoder.dashboard.modules.system.enums.logger.SysLoginResultEnum;
|
||||||
import cn.iocoder.dashboard.modules.system.service.auth.SysAuthService;
|
import cn.iocoder.dashboard.modules.system.service.auth.SysAuthService;
|
||||||
import cn.iocoder.dashboard.modules.system.service.auth.SysTokenService;
|
import cn.iocoder.dashboard.modules.system.service.auth.SysUserSessionService;
|
||||||
import cn.iocoder.dashboard.modules.system.service.common.SysCaptchaService;
|
import cn.iocoder.dashboard.modules.system.service.common.SysCaptchaService;
|
||||||
import cn.iocoder.dashboard.modules.system.service.logger.SysLoginLogService;
|
import cn.iocoder.dashboard.modules.system.service.logger.SysLoginLogService;
|
||||||
import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService;
|
import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService;
|
||||||
import cn.iocoder.dashboard.modules.system.service.user.SysUserService;
|
import cn.iocoder.dashboard.modules.system.service.user.SysUserService;
|
||||||
import cn.iocoder.dashboard.util.date.DateUtils;
|
|
||||||
import cn.iocoder.dashboard.util.servlet.ServletUtils;
|
import cn.iocoder.dashboard.util.servlet.ServletUtils;
|
||||||
import io.jsonwebtoken.Claims;
|
|
||||||
import io.jsonwebtoken.JwtException;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.authentication.BadCredentialsException;
|
import org.springframework.security.authentication.BadCredentialsException;
|
||||||
@ -37,7 +31,6 @@ import org.springframework.util.Assert;
|
|||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import static cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
@ -52,11 +45,6 @@ import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class SysAuthServiceImpl implements SysAuthService {
|
public class SysAuthServiceImpl implements SysAuthService {
|
||||||
|
|
||||||
@Resource
|
|
||||||
private SecurityProperties securityProperties;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private SysTokenService tokenService;
|
|
||||||
@Resource
|
@Resource
|
||||||
private AuthenticationManager authenticationManager;
|
private AuthenticationManager authenticationManager;
|
||||||
@Resource
|
@Resource
|
||||||
@ -67,9 +55,8 @@ public class SysAuthServiceImpl implements SysAuthService {
|
|||||||
private SysCaptchaService captchaService;
|
private SysCaptchaService captchaService;
|
||||||
@Resource
|
@Resource
|
||||||
private SysLoginLogService loginLogService;
|
private SysLoginLogService loginLogService;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private SysLoginUserRedisDAO loginUserRedisDAO;
|
private SysUserSessionService userSessionService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||||
@ -91,27 +78,21 @@ public class SysAuthServiceImpl implements SysAuthService {
|
|||||||
}
|
}
|
||||||
// 创建 LoginUser 对象
|
// 创建 LoginUser 对象
|
||||||
LoginUser loginUser = SysAuthConvert.INSTANCE.convert(user);
|
LoginUser loginUser = SysAuthConvert.INSTANCE.convert(user);
|
||||||
loginUser.setUpdateTime(new Date());
|
loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId())); // 获取用户角色列表
|
||||||
loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId()));
|
|
||||||
return loginUser;
|
return loginUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String login(String username, String password, String captchaUUID, String captchaCode) {
|
public String login(SysAuthLoginReqVO reqVO, String userIp, String userAgent) {
|
||||||
// 判断验证码是否正确
|
// 判断验证码是否正确
|
||||||
this.verifyCaptcha(username, captchaUUID, captchaCode);
|
this.verifyCaptcha(reqVO.getUsername(), reqVO.getUuid(), reqVO.getCode());
|
||||||
|
|
||||||
// 使用账号密码,进行登陆。
|
// 使用账号密码,进行登陆。
|
||||||
LoginUser loginUser = this.login0(username, password);
|
LoginUser loginUser = this.login0(reqVO.getUsername(), reqVO.getPassword());
|
||||||
// 缓存登陆用户到 Redis 中
|
loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId())); // 获取用户角色列表
|
||||||
String sessionId = IdUtil.fastSimpleUUID();
|
|
||||||
loginUser.setUpdateTime(new Date());
|
|
||||||
loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId()));
|
|
||||||
loginUserRedisDAO.set(sessionId, loginUser);
|
|
||||||
|
|
||||||
// 创建 Token
|
// 缓存登陆用户到 Redis 中,返回 sessionId 编号
|
||||||
// 我们在返回给前端的 JWT 中,使用 sessionId 作为 subject 主体,标识当前 User 用户
|
return userSessionService.createUserSession(loginUser, userIp, userAgent);
|
||||||
return tokenService.createToken(sessionId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void verifyCaptcha(String username, String captchaUUID, String captchaCode) {
|
private void verifyCaptcha(String username, String captchaUUID, String captchaCode) {
|
||||||
@ -182,42 +163,20 @@ public class SysAuthServiceImpl implements SysAuthService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LoginUser verifyTokenAndRefresh(String token) {
|
public LoginUser verifyTokenAndRefresh(String token) {
|
||||||
// 验证 token 的有效性
|
|
||||||
String sessionId = this.verifyToken(token);
|
|
||||||
// 获得 LoginUser
|
// 获得 LoginUser
|
||||||
LoginUser loginUser = loginUserRedisDAO.get(sessionId);
|
LoginUser loginUser = userSessionService.getLoginUser(token);
|
||||||
if (loginUser == null) {
|
if (loginUser == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// 刷新 LoginUser 缓存
|
// 刷新 LoginUser 缓存
|
||||||
this.refreshLoginUserCache(sessionId, loginUser);
|
this.refreshLoginUserCache(token, loginUser);
|
||||||
return loginUser;
|
return loginUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String verifyToken(String token) {
|
private void refreshLoginUserCache(String token, LoginUser loginUser) {
|
||||||
Claims claims;
|
|
||||||
try {
|
|
||||||
claims = tokenService.parseToken(token);
|
|
||||||
} catch (JwtException jwtException) {
|
|
||||||
log.warn("[verifyToken][token({}) 解析发生异常]", token);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
// token 已经过期
|
|
||||||
if (DateUtils.isExpired(claims.getExpiration())) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
// 判断 sessionId 是否存在
|
|
||||||
String sessionId = claims.getSubject();
|
|
||||||
if (StrUtil.isBlank(sessionId)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return sessionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void refreshLoginUserCache(String sessionId, LoginUser loginUser) {
|
|
||||||
// 每 1/3 的 Session 超时时间,刷新 LoginUser 缓存
|
// 每 1/3 的 Session 超时时间,刷新 LoginUser 缓存
|
||||||
if (System.currentTimeMillis() - loginUser.getUpdateTime().getTime() <
|
if (System.currentTimeMillis() - loginUser.getUpdateTime().getTime() <
|
||||||
securityProperties.getSessionTimeout().toMillis() / 3) {
|
userSessionService.getSessionTimeoutMillis() / 3) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,9 +188,8 @@ public class SysAuthServiceImpl implements SysAuthService {
|
|||||||
|
|
||||||
// 刷新 LoginUser 缓存
|
// 刷新 LoginUser 缓存
|
||||||
loginUser.setDeptId(user.getDeptId());
|
loginUser.setDeptId(user.getDeptId());
|
||||||
loginUser.setUpdateTime(new Date());
|
|
||||||
loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId()));
|
loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId()));
|
||||||
loginUserRedisDAO.set(sessionId, loginUser);
|
userSessionService.refreshUserSession(token, loginUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,58 +0,0 @@
|
|||||||
package cn.iocoder.dashboard.modules.system.service.auth.impl;
|
|
||||||
|
|
||||||
import cn.iocoder.dashboard.framework.security.config.SecurityProperties;
|
|
||||||
import cn.iocoder.dashboard.modules.system.service.auth.SysTokenService;
|
|
||||||
import cn.iocoder.dashboard.util.date.DateUtils;
|
|
||||||
import io.jsonwebtoken.Claims;
|
|
||||||
import io.jsonwebtoken.Jwts;
|
|
||||||
import io.jsonwebtoken.SignatureAlgorithm;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Token Service 实现类
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Service
|
|
||||||
public class SysTokenServiceImpl implements SysTokenService {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private SecurityProperties securityProperties;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String createToken(String subject) {
|
|
||||||
return Jwts.builder()
|
|
||||||
.signWith(SignatureAlgorithm.HS512, securityProperties.getTokenSecret())
|
|
||||||
.setExpiration(DateUtils.addTime(securityProperties.getTokenTimeout()))
|
|
||||||
.setSubject(subject)
|
|
||||||
.compact();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Claims parseToken(String token) {
|
|
||||||
return Jwts.parser()
|
|
||||||
.setSigningKey(securityProperties.getTokenSecret())
|
|
||||||
.parseClaimsJws(token)
|
|
||||||
.getBody();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
String secret = "abcdefghijklmnopqrstuvwxyz";
|
|
||||||
Map<String, Object> map = new HashMap<>();
|
|
||||||
map.put("key1", "value1");
|
|
||||||
System.out.println(Jwts.builder()
|
|
||||||
.signWith(SignatureAlgorithm.HS512, secret)
|
|
||||||
.setClaims(map)
|
|
||||||
.compact());
|
|
||||||
|
|
||||||
System.out.println(Jwts.parser()
|
|
||||||
.setSigningKey(secret)
|
|
||||||
.parseClaimsJws("qyJhbGciOiJIUzUxMiJ9.eyJrZXkxIjoidmFsdWUxIn0.AHWncLRBlJkqrKaoWHZmMgbqYIT7rfLs8KCp9LuC0mdNfnx1xEMm1N9bgcD-0lc5sjySqsKiWzqJ3rpoyUSh0g")
|
|
||||||
.getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,89 @@
|
|||||||
|
package cn.iocoder.dashboard.modules.system.service.auth.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.IdUtil;
|
||||||
|
import cn.iocoder.dashboard.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.dashboard.framework.security.config.SecurityProperties;
|
||||||
|
import cn.iocoder.dashboard.framework.security.core.LoginUser;
|
||||||
|
import cn.iocoder.dashboard.modules.system.controller.auth.vo.session.SysUserSessionPageReqVO;
|
||||||
|
import cn.iocoder.dashboard.modules.system.dal.mysql.dao.auth.SysUserSessionMapper;
|
||||||
|
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.auth.SysUserSessionDO;
|
||||||
|
import cn.iocoder.dashboard.modules.system.dal.redis.dao.auth.SysLoginUserRedisDAO;
|
||||||
|
import cn.iocoder.dashboard.modules.system.service.auth.SysUserSessionService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在线用户 Session Service 实现类
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class SysUserSessionServiceImpl implements SysUserSessionService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SecurityProperties securityProperties;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SysLoginUserRedisDAO loginUserRedisDAO;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SysUserSessionMapper userSessionMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String createUserSession(LoginUser loginUser, String userIp, String userAgent) {
|
||||||
|
// 生成 Session 编号
|
||||||
|
String sessionId = generateSessionId();
|
||||||
|
// 写入 Redis 缓存
|
||||||
|
loginUser.setUpdateTime(new Date());
|
||||||
|
loginUserRedisDAO.set(sessionId, loginUser);
|
||||||
|
// 写入 DB 中
|
||||||
|
SysUserSessionDO userSession = SysUserSessionDO.builder().userId(loginUser.getId())
|
||||||
|
.userIp(userIp).userAgent(userAgent).build();
|
||||||
|
userSessionMapper.insert(userSession);
|
||||||
|
// 返回 Session 编号
|
||||||
|
return sessionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void refreshUserSession(String sessionId, LoginUser loginUser) {
|
||||||
|
// 写入 Redis 缓存
|
||||||
|
loginUser.setUpdateTime(new Date());
|
||||||
|
loginUserRedisDAO.set(sessionId, loginUser);
|
||||||
|
// 更新 DB 中
|
||||||
|
SysUserSessionDO updateObj = SysUserSessionDO.builder().id(sessionId).build();
|
||||||
|
updateObj.setUpdateTime(new Date());
|
||||||
|
userSessionMapper.updateById(updateObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteUserSession(String sessionId) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LoginUser getLoginUser(String sessionId) {
|
||||||
|
return loginUserRedisDAO.get(sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getSessionTimeoutMillis() {
|
||||||
|
return securityProperties.getSessionTimeout().toMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageResult<SysUserSessionDO> getUserSessionPage(SysUserSessionPageReqVO reqVO) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成 Session 编号,目前采用 UUID 算法
|
||||||
|
*
|
||||||
|
* @return Session 编号
|
||||||
|
*/
|
||||||
|
private static String generateSessionId() {
|
||||||
|
return IdUtil.fastSimpleUUID();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -41,6 +41,7 @@ spring:
|
|||||||
|
|
||||||
# 芋道配置项,设置当前项目所有自定义的配置
|
# 芋道配置项,设置当前项目所有自定义的配置
|
||||||
yudao:
|
yudao:
|
||||||
|
version: 1.0.0
|
||||||
web:
|
web:
|
||||||
api-prefix: /api
|
api-prefix: /api
|
||||||
controller-package: cn.iocoder.dashboard
|
controller-package: cn.iocoder.dashboard
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
Application Version: ${ruoyi.version}
|
芋道源码 http://www.iocoder.cn
|
||||||
|
Application Version: ${yudao.version}
|
||||||
Spring Boot Version: ${spring-boot.version}
|
Spring Boot Version: ${spring-boot.version}
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// _ooOoo_ //
|
// _ooOoo_ //
|
Loading…
Reference in New Issue
Block a user