Commit ab94fe2d4b1ec7593b684056d33efd83b2a08258

Authored by YunaiV
1 parent b557251b

将 LoginUser 重构到 UserSessionService 模块汇总

Showing 20 changed files with 283 additions and 328 deletions
@@ -53,7 +53,6 @@ @@ -53,7 +53,6 @@
53 <!-- 工具类相关 --> 53 <!-- 工具类相关 -->
54 <lombok.version>1.16.14</lombok.version> 54 <lombok.version>1.16.14</lombok.version>
55 <mapstruct.version>1.4.1.Final</mapstruct.version> 55 <mapstruct.version>1.4.1.Final</mapstruct.version>
56 - <jjwt.version>0.9.1</jjwt.version>  
57 <hutool.version>5.5.6</hutool.version> 56 <hutool.version>5.5.6</hutool.version>
58 <easyexcel.verion>2.2.7</easyexcel.verion> 57 <easyexcel.verion>2.2.7</easyexcel.verion>
59 </properties> 58 </properties>
@@ -178,12 +177,6 @@ @@ -178,12 +177,6 @@
178 </dependency> 177 </dependency>
179 178
180 <dependency> 179 <dependency>
181 - <groupId>io.jsonwebtoken</groupId>  
182 - <artifactId>jjwt</artifactId>  
183 - <version>${jjwt.version}</version>  
184 - </dependency>  
185 -  
186 - <dependency>  
187 <groupId>org.projectlombok</groupId> 180 <groupId>org.projectlombok</groupId>
188 <artifactId>lombok</artifactId> 181 <artifactId>lombok</artifactId>
189 <version>${lombok.version}</version> 182 <version>${lombok.version}</version>
ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java deleted
1 -package com.ruoyi;  
2 -  
3 -import org.springframework.boot.SpringApplication;  
4 -import org.springframework.boot.autoconfigure.SpringBootApplication;  
5 -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;  
6 -  
7 -/**  
8 - * 启动程序  
9 - *  
10 - * @author ruoyi  
11 - */  
12 -@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })  
13 -public class RuoYiApplication  
14 -{  
15 - public static void main(String[] args)  
16 - {  
17 - // System.setProperty("spring.devtools.restart.enabled", "false");  
18 - SpringApplication.run(RuoYiApplication.class, args);  
19 - System.out.println("(♥◠‿◠)ノ゙ 若依启动成功 ლ(´ڡ`ლ)゙ \n" +  
20 - " .-------. ____ __ \n" +  
21 - " | _ _ \\ \\ \\ / / \n" +  
22 - " | ( ' ) | \\ _. / ' \n" +  
23 - " |(_ o _) / _( )_ .' \n" +  
24 - " | (_,_).' __ ___(_ o _)' \n" +  
25 - " | |\\ \\ | || |(_,_)' \n" +  
26 - " | | \\ `' /| `-' / \n" +  
27 - " | | \\ / \\ / \n" +  
28 - " ''-' `'-' `-..-' ");  
29 - }  
30 -}  
ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java deleted
1 -package com.ruoyi.web.controller.monitor;  
2 -  
3 -import java.util.ArrayList;  
4 -import java.util.Collection;  
5 -import java.util.Collections;  
6 -import java.util.List;  
7 -import org.springframework.beans.factory.annotation.Autowired;  
8 -import org.springframework.security.access.prepost.PreAuthorize;  
9 -import org.springframework.web.bind.annotation.DeleteMapping;  
10 -import org.springframework.web.bind.annotation.GetMapping;  
11 -import org.springframework.web.bind.annotation.PathVariable;  
12 -import org.springframework.web.bind.annotation.RequestMapping;  
13 -import org.springframework.web.bind.annotation.RestController;  
14 -import com.ruoyi.common.annotation.Log;  
15 -import com.ruoyi.common.constant.Constants;  
16 -import com.ruoyi.common.core.controller.BaseController;  
17 -import com.ruoyi.common.core.domain.AjaxResult;  
18 -import com.ruoyi.common.core.domain.model.LoginUser;  
19 -import com.ruoyi.common.core.page.TableDataInfo;  
20 -import com.ruoyi.common.core.redis.RedisCache;  
21 -import com.ruoyi.common.enums.BusinessType;  
22 -import com.ruoyi.common.utils.StringUtils;  
23 -import com.ruoyi.system.domain.SysUserOnline;  
24 -import com.ruoyi.system.service.ISysUserOnlineService;  
25 -  
26 -/**  
27 - * 在线用户监控  
28 - *  
29 - * @author ruoyi  
30 - */  
31 -@RestController  
32 -@RequestMapping("/monitor/online")  
33 -public class SysUserOnlineController extends BaseController  
34 -{  
35 - @Autowired  
36 - private ISysUserOnlineService userOnlineService;  
37 -  
38 - @Autowired  
39 - private RedisCache redisCache;  
40 -  
41 - @PreAuthorize("@ss.hasPermi('monitor:online:list')")  
42 - @GetMapping("/list")  
43 - public TableDataInfo list(String ipaddr, String userName)  
44 - {  
45 - Collection<String> keys = redisCache.keys(Constants.LOGIN_TOKEN_KEY + "*");  
46 - List<SysUserOnline> userOnlineList = new ArrayList<SysUserOnline>();  
47 - for (String key : keys)  
48 - {  
49 - LoginUser user = redisCache.getCacheObject(key);  
50 - if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName))  
51 - {  
52 - if (StringUtils.equals(ipaddr, user.getIpaddr()) && StringUtils.equals(userName, user.getUsername()))  
53 - {  
54 - userOnlineList.add(userOnlineService.selectOnlineByInfo(ipaddr, userName, user));  
55 - }  
56 - }  
57 - else if (StringUtils.isNotEmpty(ipaddr))  
58 - {  
59 - if (StringUtils.equals(ipaddr, user.getIpaddr()))  
60 - {  
61 - userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr, user));  
62 - }  
63 - }  
64 - else if (StringUtils.isNotEmpty(userName) && StringUtils.isNotNull(user.getUser()))  
65 - {  
66 - if (StringUtils.equals(userName, user.getUsername()))  
67 - {  
68 - userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user));  
69 - }  
70 - }  
71 - else  
72 - {  
73 - userOnlineList.add(userOnlineService.loginUserToUserOnline(user));  
74 - }  
75 - }  
76 - Collections.reverse(userOnlineList);  
77 - userOnlineList.removeAll(Collections.singleton(null));  
78 - return getDataTable(userOnlineList);  
79 - }  
80 -  
81 - /**  
82 - * 强退用户  
83 - */  
84 - @PreAuthorize("@ss.hasPermi('monitor:online:forceLogout')")  
85 - @Log(title = "在线用户", businessType = BusinessType.FORCE)  
86 - @DeleteMapping("/{tokenId}")  
87 - public AjaxResult forceLogout(@PathVariable String tokenId)  
88 - {  
89 - redisCache.deleteObject(Constants.LOGIN_TOKEN_KEY + tokenId);  
90 - return AjaxResult.success();  
91 - }  
92 -}  
ruoyi-admin/src/main/resources/META-INF/spring-devtools.properties deleted
1 -restart.include.json=/com.alibaba.fastjson.*.jar  
2 \ No newline at end of file 0 \ No newline at end of file
ruoyi-admin/src/main/resources/application.yml
@@ -34,20 +34,6 @@ logging: @@ -34,20 +34,6 @@ logging:
34 com.ruoyi: debug 34 com.ruoyi: debug
35 org.springframework: warn 35 org.springframework: warn
36 36
37 -# Spring配置  
38 -spring:  
39 - # 资源信息  
40 - messages:  
41 - # 国际化资源文件路径  
42 - basename: i18n/messages  
43 - profiles:  
44 - active: druid  
45 - # 服务模块  
46 - devtools:  
47 - restart:  
48 - # 热部署开关  
49 - enabled: true  
50 -  
51 # 防止XSS攻击 37 # 防止XSS攻击
52 xss: 38 xss:
53 # 过滤开关 39 # 过滤开关
src/main/java/cn/iocoder/dashboard/framework/mybatis/core/dataobject/BaseDO.java
@@ -34,7 +34,4 @@ public class BaseDO implements Serializable { @@ -34,7 +34,4 @@ public class BaseDO implements Serializable {
34 @TableLogic 34 @TableLogic
35 private Integer deleted; 35 private Integer deleted;
36 36
37 -// /** 备注 */ TODO 思考下,怎么解决  
38 -// private String remark;  
39 -  
40 } 37 }
src/main/java/cn/iocoder/dashboard/modules/system/controller/auth/SysAuthController.java
@@ -28,6 +28,8 @@ import java.util.List; @@ -28,6 +28,8 @@ import java.util.List;
28 import static cn.iocoder.dashboard.common.pojo.CommonResult.success; 28 import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
29 import static cn.iocoder.dashboard.framework.security.core.util.SecurityUtils.getLoginUserId; 29 import static cn.iocoder.dashboard.framework.security.core.util.SecurityUtils.getLoginUserId;
30 import static cn.iocoder.dashboard.framework.security.core.util.SecurityUtils.getLoginUserRoleIds; 30 import static cn.iocoder.dashboard.framework.security.core.util.SecurityUtils.getLoginUserRoleIds;
  31 +import static cn.iocoder.dashboard.util.servlet.ServletUtils.getClientIP;
  32 +import static cn.iocoder.dashboard.util.servlet.ServletUtils.getUserAgent;
31 33
32 @Api("认证 API") 34 @Api("认证 API")
33 @RestController 35 @RestController
@@ -47,7 +49,7 @@ public class SysAuthController { @@ -47,7 +49,7 @@ public class SysAuthController {
47 @PostMapping("/login") 49 @PostMapping("/login")
48 @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 50 @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
49 public CommonResult<SysAuthLoginRespVO> login(@RequestBody @Valid SysAuthLoginReqVO reqVO) { 51 public CommonResult<SysAuthLoginRespVO> login(@RequestBody @Valid SysAuthLoginReqVO reqVO) {
50 - String token = authService.login(reqVO.getUsername(), reqVO.getPassword(), reqVO.getUuid(), reqVO.getCode()); 52 + String token = authService.login(reqVO, getClientIP(), getUserAgent());
51 // 返回结果 53 // 返回结果
52 return success(SysAuthLoginRespVO.builder().token(token).build()); 54 return success(SysAuthLoginRespVO.builder().token(token).build());
53 } 55 }
src/main/java/cn/iocoder/dashboard/modules/system/controller/auth/SysUserSessionController.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.controller.auth;
  2 +
  3 +import cn.iocoder.dashboard.common.pojo.CommonResult;
  4 +import cn.iocoder.dashboard.common.pojo.PageResult;
  5 +import cn.iocoder.dashboard.modules.system.controller.auth.vo.session.SysUserSessionPageItemRespVO;
  6 +import cn.iocoder.dashboard.modules.system.controller.auth.vo.session.SysUserSessionPageReqVO;
  7 +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.auth.SysUserSessionDO;
  8 +import cn.iocoder.dashboard.modules.system.service.auth.SysUserSessionService;
  9 +import io.swagger.annotations.Api;
  10 +import io.swagger.annotations.ApiImplicitParam;
  11 +import io.swagger.annotations.ApiOperation;
  12 +import org.springframework.security.access.prepost.PreAuthorize;
  13 +import org.springframework.validation.annotation.Validated;
  14 +import org.springframework.web.bind.annotation.*;
  15 +
  16 +import javax.annotation.Resource;
  17 +
  18 +import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
  19 +
  20 +@Api("用户 Session API")
  21 +@RestController
  22 +@RequestMapping("/user-session")
  23 +public class SysUserSessionController {
  24 +
  25 + @Resource
  26 + private SysUserSessionService userSessionService;
  27 +
  28 + @ApiOperation("获得 Session 分页列表")
  29 + @PreAuthorize("@ss.hasPermission('system:user-session:page')")
  30 + @GetMapping("/page")
  31 + public CommonResult<PageResult<SysUserSessionPageItemRespVO>> getUserSessionPage(@Validated SysUserSessionPageReqVO reqVO) {
  32 + // 获得 Session 分页
  33 + PageResult<SysUserSessionDO> sessionPage = userSessionService.getUserSessionPage(reqVO);
  34 +
  35 + //
  36 + return null;
  37 + }
  38 +
  39 + @ApiOperation("删除 Session")
  40 + @PreAuthorize("@ss.hasPermission('system:user-session:delete')")
  41 + @DeleteMapping("/delete")
  42 + @ApiImplicitParam(name = "id", value = "Session 编号", required = true, dataTypeClass = String.class,
  43 + example = "fe50b9f6-d177-44b1-8da9-72ea34f63db7")
  44 + public CommonResult<Boolean> delete(@RequestParam("id") String id) {
  45 + userSessionService.deleteUserSession(id);
  46 + return success(true);
  47 + }
  48 +
  49 +}
src/main/java/cn/iocoder/dashboard/modules/system/controller/auth/vo/session/SysUserSessionPageItemRespVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.controller.auth.vo.session;
  2 +
  3 +import cn.iocoder.dashboard.common.pojo.PageParam;
  4 +import io.swagger.annotations.ApiModel;
  5 +import io.swagger.annotations.ApiModelProperty;
  6 +import lombok.AllArgsConstructor;
  7 +import lombok.Data;
  8 +import lombok.EqualsAndHashCode;
  9 +import lombok.NoArgsConstructor;
  10 +
  11 +@ApiModel(value = "用户在线 Session Response VO", description = "相比用户基本信息来说,会多部门、用户账号等信息")
  12 +@Data
  13 +@NoArgsConstructor
  14 +@AllArgsConstructor
  15 +@EqualsAndHashCode(callSuper = true)
  16 +public class SysUserSessionPageItemRespVO extends PageParam {
  17 +
  18 + @ApiModelProperty(value = "Session 编号", required = true, example = "fe50b9f6-d177-44b1-8da9-72ea34f63db7")
  19 + private String id;
  20 +
  21 + @ApiModelProperty(value = "用户 IP", required = true, example = "127.0.0.1")
  22 + private String userIp;
  23 +
  24 + @ApiModelProperty(value = "浏览器 UserAgent", required = true, example = "Mozilla/5.0")
  25 + private String userAgent;
  26 +
  27 + @ApiModelProperty(value = "登陆时间", required = true)
  28 + private String createTime;
  29 +
  30 + @ApiModelProperty(value = "用户账号", required = true, example = "yudao")
  31 + private String username;
  32 +
  33 + @ApiModelProperty(value = "部门名称", example = "研发部")
  34 + private String deptName;
  35 +
  36 +}
src/main/java/cn/iocoder/dashboard/modules/system/controller/auth/vo/session/SysUserSessionPageReqVO.java
@@ -2,11 +2,22 @@ package cn.iocoder.dashboard.modules.system.controller.auth.vo.session; @@ -2,11 +2,22 @@ package cn.iocoder.dashboard.modules.system.controller.auth.vo.session;
2 2
3 import cn.iocoder.dashboard.common.pojo.PageParam; 3 import cn.iocoder.dashboard.common.pojo.PageParam;
4 import io.swagger.annotations.ApiModel; 4 import io.swagger.annotations.ApiModel;
  5 +import io.swagger.annotations.ApiModelProperty;
5 import lombok.Data; 6 import lombok.Data;
6 import lombok.EqualsAndHashCode; 7 import lombok.EqualsAndHashCode;
7 8
  9 +import javax.validation.constraints.NotEmpty;
  10 +
8 @ApiModel("在线用户 Session 分页 Request VO") 11 @ApiModel("在线用户 Session 分页 Request VO")
9 @Data 12 @Data
10 @EqualsAndHashCode(callSuper = true) 13 @EqualsAndHashCode(callSuper = true)
11 public class SysUserSessionPageReqVO extends PageParam { 14 public class SysUserSessionPageReqVO extends PageParam {
  15 +
  16 + @ApiModelProperty(value = "用户 IP", example = "127.0.0.1", notes = "模糊匹配")
  17 + @NotEmpty(message = "用户 IP 不能为空")
  18 + private String userIp;
  19 +
  20 + @ApiModelProperty(value = "用户账号", example = "yudao", notes = "模糊匹配")
  21 + private String username;
  22 +
12 } 23 }
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/auth/SysUserOnlineMapper.java renamed to src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/auth/SysUserSessionMapper.java
@@ -2,6 +2,8 @@ package cn.iocoder.dashboard.modules.system.dal.mysql.dao.auth; @@ -2,6 +2,8 @@ package cn.iocoder.dashboard.modules.system.dal.mysql.dao.auth;
2 2
3 import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.auth.SysUserSessionDO; 3 import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.auth.SysUserSessionDO;
4 import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  5 +import org.apache.ibatis.annotations.Mapper;
5 6
6 -public interface SysUserOnlineMapper extends BaseMapper<SysUserSessionDO> { 7 +@Mapper
  8 +public interface SysUserSessionMapper extends BaseMapper<SysUserSessionDO> {
7 } 9 }
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/auth/SysUserSessionDO.java
1 package cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.auth; 1 package cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.auth;
2 2
3 import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO; 3 import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO;
  4 +import cn.iocoder.dashboard.framework.security.core.LoginUser;
4 import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO; 5 import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO;
5 import com.baomidou.mybatisplus.annotation.TableId; 6 import com.baomidou.mybatisplus.annotation.TableId;
6 import com.baomidou.mybatisplus.annotation.TableName; 7 import com.baomidou.mybatisplus.annotation.TableName;
  8 +import lombok.Builder;
7 import lombok.Data; 9 import lombok.Data;
8 import lombok.EqualsAndHashCode; 10 import lombok.EqualsAndHashCode;
9 11
10 /** 12 /**
11 * 在线用户表 13 * 在线用户表
  14 + *
  15 + * 我们已经将 {@link LoginUser} 缓存在 Redis 当中。
  16 + * 这里额外存储在线用户到 MySQL 中,目的是为了方便管理界面可以灵活查询。
  17 + * 同时,通过定时轮询 SysUserSessionDO 表,可以主动删除 Redis 的缓存,因为 Redis 的过期删除是延迟的。
  18 + *
  19 + * @author 芋道源码
12 */ 20 */
13 @TableName(value = "sys_user_session", autoResultMap = true) 21 @TableName(value = "sys_user_session", autoResultMap = true)
14 @Data 22 @Data
  23 +@Builder
15 @EqualsAndHashCode(callSuper = true) 24 @EqualsAndHashCode(callSuper = true)
16 public class SysUserSessionDO extends BaseDO { 25 public class SysUserSessionDO extends BaseDO {
17 26
src/main/java/cn/iocoder/dashboard/modules/system/service/auth/SysAuthService.java
1 package cn.iocoder.dashboard.modules.system.service.auth; 1 package cn.iocoder.dashboard.modules.system.service.auth;
2 2
3 import cn.iocoder.dashboard.framework.security.core.service.SecurityAuthFrameworkService; 3 import cn.iocoder.dashboard.framework.security.core.service.SecurityAuthFrameworkService;
  4 +import cn.iocoder.dashboard.modules.system.controller.auth.vo.auth.SysAuthLoginReqVO;
4 5
5 /** 6 /**
6 * 认证 Service 接口 7 * 认证 Service 接口
@@ -11,6 +12,14 @@ import cn.iocoder.dashboard.framework.security.core.service.SecurityAuthFramewor @@ -11,6 +12,14 @@ import cn.iocoder.dashboard.framework.security.core.service.SecurityAuthFramewor
11 */ 12 */
12 public interface SysAuthService extends SecurityAuthFrameworkService { 13 public interface SysAuthService extends SecurityAuthFrameworkService {
13 14
14 - String login(String username, String password, String captchaUUID, String captchaCode); 15 + /**
  16 + * 登陆用户
  17 + *
  18 + * @param reqVO 登陆信息
  19 + * @param userIp 用户 IP
  20 + * @param userAgent 用户 UA
  21 + * @return 身份令牌,使用 JWT 方式
  22 + */
  23 + String login(SysAuthLoginReqVO reqVO, String userIp, String userAgent);
15 24
16 } 25 }
src/main/java/cn/iocoder/dashboard/modules/system/service/auth/SysTokenService.java deleted
1 -package cn.iocoder.dashboard.modules.system.service.auth;  
2 -  
3 -import io.jsonwebtoken.Claims;  
4 -  
5 -import java.util.Map;  
6 -  
7 -/**  
8 - * Token Service 接口  
9 - *  
10 - * 提供访问 Token 令牌,目前基于 JWT 实现  
11 - */  
12 -public interface SysTokenService {  
13 -  
14 - /**  
15 - * 创建 Token  
16 - *  
17 - * @param subject 主体  
18 - * @return Token 字符串  
19 - */  
20 - String createToken(String subject);  
21 -  
22 - /**  
23 - * 解析 Token,返回 claims 数据声明  
24 - *  
25 - * @param token Token  
26 - * @return claims  
27 - */  
28 - Claims parseToken(String token);  
29 -  
30 -}  
src/main/java/cn/iocoder/dashboard/modules/system/service/auth/SysUserOnlineService.java renamed to src/main/java/cn/iocoder/dashboard/modules/system/service/auth/SysUserSessionService.java
1 package cn.iocoder.dashboard.modules.system.service.auth; 1 package cn.iocoder.dashboard.modules.system.service.auth;
2 2
3 import cn.iocoder.dashboard.common.pojo.PageResult; 3 import cn.iocoder.dashboard.common.pojo.PageResult;
  4 +import cn.iocoder.dashboard.framework.security.core.LoginUser;
4 import cn.iocoder.dashboard.modules.system.controller.auth.vo.session.SysUserSessionPageReqVO; 5 import cn.iocoder.dashboard.modules.system.controller.auth.vo.session.SysUserSessionPageReqVO;
5 import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.auth.SysUserSessionDO; 6 import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.auth.SysUserSessionDO;
6 7
7 -import java.util.Date;  
8 -  
9 /** 8 /**
10 * 在线用户 Session Service 接口 9 * 在线用户 Session Service 接口
  10 + *
  11 + * @author 芋道源码
11 */ 12 */
12 -public interface SysUserOnlineService { 13 +public interface SysUserSessionService {
13 14
14 /** 15 /**
15 * 创建在线用户 Session 16 * 创建在线用户 Session
16 * 17 *
17 - * @param sessionId Session 编号  
18 - * @param userId 用户编号 18 + * @param loginUser 登陆用户
19 * @param userIp 用户 IP 19 * @param userIp 用户 IP
20 * @param userAgent 用户 UA 20 * @param userAgent 用户 UA
  21 + * @return Session 编号
  22 + */
  23 + String createUserSession(LoginUser loginUser, String userIp, String userAgent);
  24 +
  25 + /**
  26 + * 刷新在线用户 Session 的更新时间
  27 + *
  28 + * @param sessionId Session 编号
  29 + * @param loginUser 登陆用户
  30 + */
  31 + void refreshUserSession(String sessionId, LoginUser loginUser);
  32 +
  33 + /**
  34 + * 删除在线用户 Session
  35 + *
  36 + * @param sessionId Session 编号
21 */ 37 */
22 - void createUserOnline(String sessionId, Long userId, String userIp, String userAgent); 38 + void deleteUserSession(String sessionId);
23 39
24 /** 40 /**
25 - * 更新在线用户 Session 的更新时间 41 + * 获得 Session 编号对应的在线用户
26 * 42 *
27 * @param sessionId Session 编号 43 * @param sessionId Session 编号
28 - * @param updateTime 更新时间 44 + * @return 在线用户
  45 + */
  46 + LoginUser getLoginUser(String sessionId);
  47 +
  48 + /**
  49 + * 获得 Session 超时时间,单位:毫秒
  50 + *
  51 + * @return 超时时间
29 */ 52 */
30 - void updateUserOnlineUpdateTime(String sessionId, Date updateTime); 53 + Long getSessionTimeoutMillis();
31 54
32 /** 55 /**
33 * 获得在线用户分页列表 56 * 获得在线用户分页列表
src/main/java/cn/iocoder/dashboard/modules/system/service/auth/impl/SysAuthServiceImpl.java
1 package cn.iocoder.dashboard.modules.system.service.auth.impl; 1 package cn.iocoder.dashboard.modules.system.service.auth.impl;
2 2
3 -import cn.hutool.core.util.IdUtil;  
4 -import cn.hutool.core.util.StrUtil;  
5 import cn.iocoder.dashboard.common.enums.CommonStatusEnum; 3 import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
6 import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil; 4 import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil;
7 -import cn.iocoder.dashboard.framework.security.config.SecurityProperties;  
8 import cn.iocoder.dashboard.framework.security.core.LoginUser; 5 import cn.iocoder.dashboard.framework.security.core.LoginUser;
9 import cn.iocoder.dashboard.framework.tracer.core.util.TracerUtils; 6 import cn.iocoder.dashboard.framework.tracer.core.util.TracerUtils;
  7 +import cn.iocoder.dashboard.modules.system.controller.auth.vo.auth.SysAuthLoginReqVO;
10 import cn.iocoder.dashboard.modules.system.controller.logger.vo.loginlog.SysLoginLogCreateReqVO; 8 import cn.iocoder.dashboard.modules.system.controller.logger.vo.loginlog.SysLoginLogCreateReqVO;
11 import cn.iocoder.dashboard.modules.system.convert.auth.SysAuthConvert; 9 import cn.iocoder.dashboard.modules.system.convert.auth.SysAuthConvert;
12 import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO; 10 import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO;
13 -import cn.iocoder.dashboard.modules.system.dal.redis.dao.auth.SysLoginUserRedisDAO;  
14 import cn.iocoder.dashboard.modules.system.enums.logger.SysLoginLogTypeEnum; 11 import cn.iocoder.dashboard.modules.system.enums.logger.SysLoginLogTypeEnum;
15 import cn.iocoder.dashboard.modules.system.enums.logger.SysLoginResultEnum; 12 import cn.iocoder.dashboard.modules.system.enums.logger.SysLoginResultEnum;
16 import cn.iocoder.dashboard.modules.system.service.auth.SysAuthService; 13 import cn.iocoder.dashboard.modules.system.service.auth.SysAuthService;
17 -import cn.iocoder.dashboard.modules.system.service.auth.SysTokenService; 14 +import cn.iocoder.dashboard.modules.system.service.auth.SysUserSessionService;
18 import cn.iocoder.dashboard.modules.system.service.common.SysCaptchaService; 15 import cn.iocoder.dashboard.modules.system.service.common.SysCaptchaService;
19 import cn.iocoder.dashboard.modules.system.service.logger.SysLoginLogService; 16 import cn.iocoder.dashboard.modules.system.service.logger.SysLoginLogService;
20 import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService; 17 import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService;
21 import cn.iocoder.dashboard.modules.system.service.user.SysUserService; 18 import cn.iocoder.dashboard.modules.system.service.user.SysUserService;
22 -import cn.iocoder.dashboard.util.date.DateUtils;  
23 import cn.iocoder.dashboard.util.servlet.ServletUtils; 19 import cn.iocoder.dashboard.util.servlet.ServletUtils;
24 -import io.jsonwebtoken.Claims;  
25 -import io.jsonwebtoken.JwtException;  
26 import lombok.extern.slf4j.Slf4j; 20 import lombok.extern.slf4j.Slf4j;
27 import org.springframework.security.authentication.AuthenticationManager; 21 import org.springframework.security.authentication.AuthenticationManager;
28 import org.springframework.security.authentication.BadCredentialsException; 22 import org.springframework.security.authentication.BadCredentialsException;
@@ -37,7 +31,6 @@ import org.springframework.util.Assert; @@ -37,7 +31,6 @@ import org.springframework.util.Assert;
37 31
38 import javax.annotation.Resource; 32 import javax.annotation.Resource;
39 import java.util.Collections; 33 import java.util.Collections;
40 -import java.util.Date;  
41 import java.util.Set; 34 import java.util.Set;
42 35
43 import static cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil.exception; 36 import static cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil.exception;
@@ -53,11 +46,6 @@ import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; @@ -53,11 +46,6 @@ import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*;
53 public class SysAuthServiceImpl implements SysAuthService { 46 public class SysAuthServiceImpl implements SysAuthService {
54 47
55 @Resource 48 @Resource
56 - private SecurityProperties securityProperties;  
57 -  
58 - @Resource  
59 - private SysTokenService tokenService;  
60 - @Resource  
61 private AuthenticationManager authenticationManager; 49 private AuthenticationManager authenticationManager;
62 @Resource 50 @Resource
63 private SysUserService userService; 51 private SysUserService userService;
@@ -67,9 +55,8 @@ public class SysAuthServiceImpl implements SysAuthService { @@ -67,9 +55,8 @@ public class SysAuthServiceImpl implements SysAuthService {
67 private SysCaptchaService captchaService; 55 private SysCaptchaService captchaService;
68 @Resource 56 @Resource
69 private SysLoginLogService loginLogService; 57 private SysLoginLogService loginLogService;
70 -  
71 @Resource 58 @Resource
72 - private SysLoginUserRedisDAO loginUserRedisDAO; 59 + private SysUserSessionService userSessionService;
73 60
74 @Override 61 @Override
75 public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 62 public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
@@ -91,27 +78,21 @@ public class SysAuthServiceImpl implements SysAuthService { @@ -91,27 +78,21 @@ public class SysAuthServiceImpl implements SysAuthService {
91 } 78 }
92 // 创建 LoginUser 对象 79 // 创建 LoginUser 对象
93 LoginUser loginUser = SysAuthConvert.INSTANCE.convert(user); 80 LoginUser loginUser = SysAuthConvert.INSTANCE.convert(user);
94 - loginUser.setUpdateTime(new Date());  
95 - loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId())); 81 + loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId())); // 获取用户角色列表
96 return loginUser; 82 return loginUser;
97 } 83 }
98 84
99 @Override 85 @Override
100 - public String login(String username, String password, String captchaUUID, String captchaCode) { 86 + public String login(SysAuthLoginReqVO reqVO, String userIp, String userAgent) {
101 // 判断验证码是否正确 87 // 判断验证码是否正确
102 - this.verifyCaptcha(username, captchaUUID, captchaCode); 88 + this.verifyCaptcha(reqVO.getUsername(), reqVO.getUuid(), reqVO.getCode());
103 89
104 // 使用账号密码,进行登陆。 90 // 使用账号密码,进行登陆。
105 - LoginUser loginUser = this.login0(username, password);  
106 - // 缓存登陆用户到 Redis 中  
107 - String sessionId = IdUtil.fastSimpleUUID();  
108 - loginUser.setUpdateTime(new Date());  
109 - loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId()));  
110 - loginUserRedisDAO.set(sessionId, loginUser); 91 + LoginUser loginUser = this.login0(reqVO.getUsername(), reqVO.getPassword());
  92 + loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId())); // 获取用户角色列表
111 93
112 - // 创建 Token  
113 - // 我们在返回给前端的 JWT 中,使用 sessionId 作为 subject 主体,标识当前 User 用户  
114 - return tokenService.createToken(sessionId); 94 + // 缓存登陆用户到 Redis 中,返回 sessionId 编号
  95 + return userSessionService.createUserSession(loginUser, userIp, userAgent);
115 } 96 }
116 97
117 private void verifyCaptcha(String username, String captchaUUID, String captchaCode) { 98 private void verifyCaptcha(String username, String captchaUUID, String captchaCode) {
@@ -182,42 +163,20 @@ public class SysAuthServiceImpl implements SysAuthService { @@ -182,42 +163,20 @@ public class SysAuthServiceImpl implements SysAuthService {
182 163
183 @Override 164 @Override
184 public LoginUser verifyTokenAndRefresh(String token) { 165 public LoginUser verifyTokenAndRefresh(String token) {
185 - // 验证 token 的有效性  
186 - String sessionId = this.verifyToken(token);  
187 // 获得 LoginUser 166 // 获得 LoginUser
188 - LoginUser loginUser = loginUserRedisDAO.get(sessionId); 167 + LoginUser loginUser = userSessionService.getLoginUser(token);
189 if (loginUser == null) { 168 if (loginUser == null) {
190 return null; 169 return null;
191 } 170 }
192 // 刷新 LoginUser 缓存 171 // 刷新 LoginUser 缓存
193 - this.refreshLoginUserCache(sessionId, loginUser); 172 + this.refreshLoginUserCache(token, loginUser);
194 return loginUser; 173 return loginUser;
195 } 174 }
196 175
197 - private String verifyToken(String token) {  
198 - Claims claims;  
199 - try {  
200 - claims = tokenService.parseToken(token);  
201 - } catch (JwtException jwtException) {  
202 - log.warn("[verifyToken][token({}) 解析发生异常]", token);  
203 - return null;  
204 - }  
205 - // token 已经过期  
206 - if (DateUtils.isExpired(claims.getExpiration())) {  
207 - return null;  
208 - }  
209 - // 判断 sessionId 是否存在  
210 - String sessionId = claims.getSubject();  
211 - if (StrUtil.isBlank(sessionId)) {  
212 - return null;  
213 - }  
214 - return sessionId;  
215 - }  
216 -  
217 - private void refreshLoginUserCache(String sessionId, LoginUser loginUser) { 176 + private void refreshLoginUserCache(String token, LoginUser loginUser) {
218 // 每 1/3 的 Session 超时时间,刷新 LoginUser 缓存 177 // 每 1/3 的 Session 超时时间,刷新 LoginUser 缓存
219 if (System.currentTimeMillis() - loginUser.getUpdateTime().getTime() < 178 if (System.currentTimeMillis() - loginUser.getUpdateTime().getTime() <
220 - securityProperties.getSessionTimeout().toMillis() / 3) { 179 + userSessionService.getSessionTimeoutMillis() / 3) {
221 return; 180 return;
222 } 181 }
223 182
@@ -229,9 +188,8 @@ public class SysAuthServiceImpl implements SysAuthService { @@ -229,9 +188,8 @@ public class SysAuthServiceImpl implements SysAuthService {
229 188
230 // 刷新 LoginUser 缓存 189 // 刷新 LoginUser 缓存
231 loginUser.setDeptId(user.getDeptId()); 190 loginUser.setDeptId(user.getDeptId());
232 - loginUser.setUpdateTime(new Date());  
233 loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId())); 191 loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId()));
234 - loginUserRedisDAO.set(sessionId, loginUser); 192 + userSessionService.refreshUserSession(token, loginUser);
235 } 193 }
236 194
237 } 195 }
src/main/java/cn/iocoder/dashboard/modules/system/service/auth/impl/SysTokenServiceImpl.java deleted
1 -package cn.iocoder.dashboard.modules.system.service.auth.impl;  
2 -  
3 -import cn.iocoder.dashboard.framework.security.config.SecurityProperties;  
4 -import cn.iocoder.dashboard.modules.system.service.auth.SysTokenService;  
5 -import cn.iocoder.dashboard.util.date.DateUtils;  
6 -import io.jsonwebtoken.Claims;  
7 -import io.jsonwebtoken.Jwts;  
8 -import io.jsonwebtoken.SignatureAlgorithm;  
9 -import org.springframework.stereotype.Service;  
10 -  
11 -import javax.annotation.Resource;  
12 -import java.util.HashMap;  
13 -import java.util.Map;  
14 -  
15 -/**  
16 - * Token Service 实现类  
17 - *  
18 - * @author 芋道源码  
19 - */  
20 -@Service  
21 -public class SysTokenServiceImpl implements SysTokenService {  
22 -  
23 - @Resource  
24 - private SecurityProperties securityProperties;  
25 -  
26 - @Override  
27 - public String createToken(String subject) {  
28 - return Jwts.builder()  
29 - .signWith(SignatureAlgorithm.HS512, securityProperties.getTokenSecret())  
30 - .setExpiration(DateUtils.addTime(securityProperties.getTokenTimeout()))  
31 - .setSubject(subject)  
32 - .compact();  
33 - }  
34 -  
35 - @Override  
36 - public Claims parseToken(String token) {  
37 - return Jwts.parser()  
38 - .setSigningKey(securityProperties.getTokenSecret())  
39 - .parseClaimsJws(token)  
40 - .getBody();  
41 - }  
42 -  
43 - public static void main(String[] args) {  
44 - String secret = "abcdefghijklmnopqrstuvwxyz";  
45 - Map<String, Object> map = new HashMap<>();  
46 - map.put("key1", "value1");  
47 - System.out.println(Jwts.builder()  
48 - .signWith(SignatureAlgorithm.HS512, secret)  
49 - .setClaims(map)  
50 - .compact());  
51 -  
52 - System.out.println(Jwts.parser()  
53 - .setSigningKey(secret)  
54 - .parseClaimsJws("qyJhbGciOiJIUzUxMiJ9.eyJrZXkxIjoidmFsdWUxIn0.AHWncLRBlJkqrKaoWHZmMgbqYIT7rfLs8KCp9LuC0mdNfnx1xEMm1N9bgcD-0lc5sjySqsKiWzqJ3rpoyUSh0g")  
55 - .getBody());  
56 - }  
57 -  
58 -}  
src/main/java/cn/iocoder/dashboard/modules/system/service/auth/impl/SysUserSessionServiceImpl.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.service.auth.impl;
  2 +
  3 +import cn.hutool.core.util.IdUtil;
  4 +import cn.iocoder.dashboard.common.pojo.PageResult;
  5 +import cn.iocoder.dashboard.framework.security.config.SecurityProperties;
  6 +import cn.iocoder.dashboard.framework.security.core.LoginUser;
  7 +import cn.iocoder.dashboard.modules.system.controller.auth.vo.session.SysUserSessionPageReqVO;
  8 +import cn.iocoder.dashboard.modules.system.dal.mysql.dao.auth.SysUserSessionMapper;
  9 +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.auth.SysUserSessionDO;
  10 +import cn.iocoder.dashboard.modules.system.dal.redis.dao.auth.SysLoginUserRedisDAO;
  11 +import cn.iocoder.dashboard.modules.system.service.auth.SysUserSessionService;
  12 +import org.springframework.stereotype.Service;
  13 +
  14 +import javax.annotation.Resource;
  15 +import java.util.Date;
  16 +
  17 +/**
  18 + * 在线用户 Session Service 实现类
  19 + *
  20 + * @author 芋道源码
  21 + */
  22 +@Service
  23 +public class SysUserSessionServiceImpl implements SysUserSessionService {
  24 +
  25 + @Resource
  26 + private SecurityProperties securityProperties;
  27 +
  28 + @Resource
  29 + private SysLoginUserRedisDAO loginUserRedisDAO;
  30 +
  31 + @Resource
  32 + private SysUserSessionMapper userSessionMapper;
  33 +
  34 + @Override
  35 + public String createUserSession(LoginUser loginUser, String userIp, String userAgent) {
  36 + // 生成 Session 编号
  37 + String sessionId = generateSessionId();
  38 + // 写入 Redis 缓存
  39 + loginUser.setUpdateTime(new Date());
  40 + loginUserRedisDAO.set(sessionId, loginUser);
  41 + // 写入 DB 中
  42 + SysUserSessionDO userSession = SysUserSessionDO.builder().userId(loginUser.getId())
  43 + .userIp(userIp).userAgent(userAgent).build();
  44 + userSessionMapper.insert(userSession);
  45 + // 返回 Session 编号
  46 + return sessionId;
  47 + }
  48 +
  49 + @Override
  50 + public void refreshUserSession(String sessionId, LoginUser loginUser) {
  51 + // 写入 Redis 缓存
  52 + loginUser.setUpdateTime(new Date());
  53 + loginUserRedisDAO.set(sessionId, loginUser);
  54 + // 更新 DB 中
  55 + SysUserSessionDO updateObj = SysUserSessionDO.builder().id(sessionId).build();
  56 + updateObj.setUpdateTime(new Date());
  57 + userSessionMapper.updateById(updateObj);
  58 + }
  59 +
  60 + @Override
  61 + public void deleteUserSession(String sessionId) {
  62 +
  63 + }
  64 +
  65 + @Override
  66 + public LoginUser getLoginUser(String sessionId) {
  67 + return loginUserRedisDAO.get(sessionId);
  68 + }
  69 +
  70 + @Override
  71 + public Long getSessionTimeoutMillis() {
  72 + return securityProperties.getSessionTimeout().toMillis();
  73 + }
  74 +
  75 + @Override
  76 + public PageResult<SysUserSessionDO> getUserSessionPage(SysUserSessionPageReqVO reqVO) {
  77 + return null;
  78 + }
  79 +
  80 + /**
  81 + * 生成 Session 编号,目前采用 UUID 算法
  82 + *
  83 + * @return Session 编号
  84 + */
  85 + private static String generateSessionId() {
  86 + return IdUtil.fastSimpleUUID();
  87 + }
  88 +
  89 +}
src/main/resources/application.yaml
@@ -41,6 +41,7 @@ spring: @@ -41,6 +41,7 @@ spring:
41 41
42 # 芋道配置项,设置当前项目所有自定义的配置 42 # 芋道配置项,设置当前项目所有自定义的配置
43 yudao: 43 yudao:
  44 + version: 1.0.0
44 web: 45 web:
45 api-prefix: /api 46 api-prefix: /api
46 controller-package: cn.iocoder.dashboard 47 controller-package: cn.iocoder.dashboard
ruoyi-admin/src/main/resources/banner.txt renamed to src/main/resources/banner.txt
1 -Application Version: ${ruoyi.version}  
2 -Spring Boot Version: ${spring-boot.version}  
3 -////////////////////////////////////////////////////////////////////  
4 -// _ooOoo_ //  
5 -// o8888888o //  
6 -// 88" . "88 //  
7 -// (| ^_^ |) //  
8 -// O\ = /O //  
9 -// ____/`---'\____ //  
10 -// .' \\| |// `. //  
11 -// / \\||| : |||// \ //  
12 -// / _||||| -:- |||||- \ //  
13 -// | | \\\ - /// | | //  
14 -// | \_| ''\---/'' | | //  
15 -// \ .-\__ `-` ___/-. / //  
16 -// ___`. .' /--.--\ `. . ___ //  
17 -// ."" '< `.___\_<|>_/___.' >'"". //  
18 -// | | : `- \`.;`\ _ /`;.`/ - ` : | | //  
19 -// \ \ `-. \_ __\ /__ _/ .-` / / //  
20 -// ========`-.____`-.___\_____/___.-`____.-'======== //  
21 -// `=---=' //  
22 -// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //  
23 -// 佛祖保佑 永不宕机 永无BUG //  
24 -////////////////////////////////////////////////////////////////////  
25 \ No newline at end of file 1 \ No newline at end of file
  2 +芋道源码 http://www.iocoder.cn
  3 +Application Version: ${yudao.version}
  4 +Spring Boot Version: ${spring-boot.version}
  5 +////////////////////////////////////////////////////////////////////
  6 +// _ooOoo_ //
  7 +// o8888888o //
  8 +// 88" . "88 //
  9 +// (| ^_^ |) //
  10 +// O\ = /O //
  11 +// ____/`---'\____ //
  12 +// .' \\| |// `. //
  13 +// / \\||| : |||// \ //
  14 +// / _||||| -:- |||||- \ //
  15 +// | | \\\ - /// | | //
  16 +// | \_| ''\---/'' | | //
  17 +// \ .-\__ `-` ___/-. / //
  18 +// ___`. .' /--.--\ `. . ___ //
  19 +// ."" '< `.___\_<|>_/___.' >'"". //
  20 +// | | : `- \`.;`\ _ /`;.`/ - ` : | | //
  21 +// \ \ `-. \_ __\ /__ _/ .-` / / //
  22 +// ========`-.____`-.___\_____/___.-`____.-'======== //
  23 +// `=---=' //
  24 +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //
  25 +// 佛祖保佑 永不宕机 永无BUG //
  26 +////////////////////////////////////////////////////////////////////