mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-11-04 04:08:43 +08:00 
			
		
		
		
	登录后,返回 OAuth2 的 access token + refresh token
This commit is contained in:
		@@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.system.api.auth;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.auth.dto.OAuth2AccessTokenCheckRespDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.auth.dto.OAuth2AccessTokenCreateReqDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.auth.dto.OAuth2AccessTokenRespDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.convert.auth.UserSessionConvert;
 | 
			
		||||
import cn.iocoder.yudao.module.system.convert.auth.OAuth2TokenConvert;
 | 
			
		||||
import cn.iocoder.yudao.module.system.service.auth.OAuth2TokenService;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
 | 
			
		||||
@@ -27,7 +27,7 @@ public class OAuth2TokenApiImpl implements OAuth2TokenApi {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public OAuth2AccessTokenCheckRespDTO checkAccessToken(String accessToken) {
 | 
			
		||||
        return UserSessionConvert.INSTANCE.convert(oauth2TokenService.checkAccessToken(accessToken));
 | 
			
		||||
        return OAuth2TokenConvert.INSTANCE.convert(oauth2TokenService.checkAccessToken(accessToken));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -61,8 +61,7 @@ public class AuthController {
 | 
			
		||||
    @ApiOperation("使用账号密码登录")
 | 
			
		||||
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
 | 
			
		||||
    public CommonResult<AuthLoginRespVO> login(@RequestBody @Valid AuthLoginReqVO reqVO) {
 | 
			
		||||
        String token = authService.login(reqVO);
 | 
			
		||||
        return success(AuthLoginRespVO.builder().token(token).build());
 | 
			
		||||
        return success(authService.login(reqVO));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @PostMapping("/logout")
 | 
			
		||||
@@ -114,9 +113,7 @@ public class AuthController {
 | 
			
		||||
    @ApiOperation("使用短信验证码登录")
 | 
			
		||||
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
 | 
			
		||||
    public CommonResult<AuthLoginRespVO> smsLogin(@RequestBody @Valid AuthSmsLoginReqVO reqVO) {
 | 
			
		||||
        String token = authService.smsLogin(reqVO);
 | 
			
		||||
        // 返回结果
 | 
			
		||||
        return success(AuthLoginRespVO.builder().token(token).build());
 | 
			
		||||
        return success(authService.smsLogin(reqVO));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @PostMapping("/send-sms-code")
 | 
			
		||||
@@ -144,16 +141,14 @@ public class AuthController {
 | 
			
		||||
    @ApiOperation("社交快捷登录,使用 code 授权码")
 | 
			
		||||
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
 | 
			
		||||
    public CommonResult<AuthLoginRespVO> socialQuickLogin(@RequestBody @Valid AuthSocialQuickLoginReqVO reqVO) {
 | 
			
		||||
        String token = authService.socialQuickLogin(reqVO);
 | 
			
		||||
        return success(AuthLoginRespVO.builder().token(token).build());
 | 
			
		||||
        return success(authService.socialQuickLogin(reqVO));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @PostMapping("/social-bind-login")
 | 
			
		||||
    @ApiOperation("社交绑定登录,使用 code 授权码 + 账号密码")
 | 
			
		||||
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
 | 
			
		||||
    public CommonResult<AuthLoginRespVO> socialBindLogin(@RequestBody @Valid AuthSocialBindLoginReqVO reqVO) {
 | 
			
		||||
        String token = authService.socialBindLogin(reqVO);
 | 
			
		||||
        return success(AuthLoginRespVO.builder().token(token).build());
 | 
			
		||||
        return success(authService.socialBindLogin(reqVO));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,81 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.controller.admin.auth;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.session.UserSessionPageItemRespVO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.session.UserSessionPageReqVO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.convert.auth.UserSessionConvert;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.dataobject.auth.UserSessionDO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.service.auth.UserSessionService;
 | 
			
		||||
import cn.iocoder.yudao.module.system.service.dept.DeptService;
 | 
			
		||||
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
 | 
			
		||||
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 java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
 | 
			
		||||
 | 
			
		||||
@Api(tags = "管理后台 - 用户 Session")
 | 
			
		||||
@RestController
 | 
			
		||||
@RequestMapping("/system/user-session")
 | 
			
		||||
public class UserSessionController {
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private UserSessionService userSessionService;
 | 
			
		||||
    @Resource
 | 
			
		||||
    private AdminUserService userService;
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private DeptService deptService;
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/page")
 | 
			
		||||
    @ApiOperation("获得 Session 分页列表")
 | 
			
		||||
    @PreAuthorize("@ss.hasPermission('system:user-session:page')")
 | 
			
		||||
    public CommonResult<PageResult<UserSessionPageItemRespVO>> getUserSessionPage(@Validated UserSessionPageReqVO reqVO) {
 | 
			
		||||
        // 获得 Session 分页
 | 
			
		||||
        PageResult<UserSessionDO> pageResult = userSessionService.getUserSessionPage(reqVO);
 | 
			
		||||
 | 
			
		||||
        // 获得拼接需要的数据
 | 
			
		||||
        Map<Long, AdminUserDO> userMap = userService.getUserMap(
 | 
			
		||||
                convertList(pageResult.getList(), UserSessionDO::getUserId,
 | 
			
		||||
                        session -> session.getUserType().equals(UserTypeEnum.ADMIN.getValue())));
 | 
			
		||||
        Map<Long, DeptDO> deptMap = deptService.getDeptMap(
 | 
			
		||||
                convertList(userMap.values(), AdminUserDO::getDeptId));
 | 
			
		||||
        // 拼接结果返回
 | 
			
		||||
        List<UserSessionPageItemRespVO> sessionList = new ArrayList<>(pageResult.getList().size());
 | 
			
		||||
        pageResult.getList().forEach(session -> {
 | 
			
		||||
            UserSessionPageItemRespVO respVO = UserSessionConvert.INSTANCE.convert(session);
 | 
			
		||||
            sessionList.add(respVO);
 | 
			
		||||
            // 设置用户账号
 | 
			
		||||
            MapUtils.findAndThen(userMap, session.getUserId(), user -> {
 | 
			
		||||
                respVO.setUsername(user.getUsername());
 | 
			
		||||
                // 设置用户部门
 | 
			
		||||
                MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> respVO.setDeptName(dept.getName()));
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
        return success(new PageResult<>(sessionList, pageResult.getTotal()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @DeleteMapping("/delete")
 | 
			
		||||
    @ApiOperation("删除 Session")
 | 
			
		||||
    @ApiImplicitParam(name = "id", value = "Session 编号", required = true, dataTypeClass = Long.class, example = "1024")
 | 
			
		||||
    @PreAuthorize("@ss.hasPermission('system:user-session:delete')")
 | 
			
		||||
    public CommonResult<Boolean> deleteUserSession(@RequestParam("id") Long id) {
 | 
			
		||||
        userSessionService.deleteUserSession(id);
 | 
			
		||||
        return success(true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -7,14 +7,25 @@ import lombok.Builder;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.NoArgsConstructor;
 | 
			
		||||
 | 
			
		||||
@ApiModel("管理后台 - 账号密码登录 Response VO")
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
 | 
			
		||||
@ApiModel("管理后台 - 登录 Response VO")
 | 
			
		||||
@Data
 | 
			
		||||
@NoArgsConstructor
 | 
			
		||||
@AllArgsConstructor
 | 
			
		||||
@Builder
 | 
			
		||||
public class AuthLoginRespVO {
 | 
			
		||||
 | 
			
		||||
    @ApiModelProperty(value = "token", required = true, example = "yudaoyuanma")
 | 
			
		||||
    private String token;
 | 
			
		||||
    @ApiModelProperty(value = "用户编号", required = true, example = "1024")
 | 
			
		||||
    private Long userId;
 | 
			
		||||
 | 
			
		||||
    @ApiModelProperty(value = "访问令牌", required = true, example = "happy")
 | 
			
		||||
    private String accessToken;
 | 
			
		||||
 | 
			
		||||
    @ApiModelProperty(value = "刷新令牌", required = true, example = "nice")
 | 
			
		||||
    private String refreshToken;
 | 
			
		||||
 | 
			
		||||
    @ApiModelProperty(value = "过期时间", required = true)
 | 
			
		||||
    private Date expiresTime;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,38 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.controller.admin.auth.vo.session;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.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;
 | 
			
		||||
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
 | 
			
		||||
@ApiModel(value = "管理后台 - 用户在线 Session Response VO", description = "相比用户基本信息来说,会多部门、用户账号等信息")
 | 
			
		||||
@Data
 | 
			
		||||
@NoArgsConstructor
 | 
			
		||||
@AllArgsConstructor
 | 
			
		||||
@EqualsAndHashCode(callSuper = true)
 | 
			
		||||
public class UserSessionPageItemRespVO 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 Date createTime;
 | 
			
		||||
 | 
			
		||||
    @ApiModelProperty(value = "用户账号", required = true, example = "yudao")
 | 
			
		||||
    private String username;
 | 
			
		||||
 | 
			
		||||
    @ApiModelProperty(value = "部门名称", example = "研发部")
 | 
			
		||||
    private String deptName;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,20 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.controller.admin.auth.vo.session;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
 | 
			
		||||
import io.swagger.annotations.ApiModel;
 | 
			
		||||
import io.swagger.annotations.ApiModelProperty;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.EqualsAndHashCode;
 | 
			
		||||
 | 
			
		||||
@ApiModel("管理后台 - 在线用户 Session 分页 Request VO")
 | 
			
		||||
@Data
 | 
			
		||||
@EqualsAndHashCode(callSuper = true)
 | 
			
		||||
public class UserSessionPageReqVO extends PageParam {
 | 
			
		||||
 | 
			
		||||
    @ApiModelProperty(value = "用户 IP", example = "127.0.0.1", notes = "模糊匹配")
 | 
			
		||||
    private String userIp;
 | 
			
		||||
 | 
			
		||||
    @ApiModelProperty(value = "用户账号", example = "yudao", notes = "模糊匹配")
 | 
			
		||||
    private String username;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,11 +1,11 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.convert.auth;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 | 
			
		||||
import cn.iocoder.yudao.framework.security.core.LoginUser;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth.*;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
 | 
			
		||||
@@ -21,7 +21,7 @@ public interface AuthConvert {
 | 
			
		||||
 | 
			
		||||
    AuthConvert INSTANCE = Mappers.getMapper(AuthConvert.class);
 | 
			
		||||
 | 
			
		||||
    LoginUser convert(AdminUserDO bean);
 | 
			
		||||
    AuthLoginRespVO convert(OAuth2AccessTokenDO bean);
 | 
			
		||||
 | 
			
		||||
    default AuthPermissionInfoRespVO convert(AdminUserDO user, List<RoleDO> roleList, List<MenuDO> menuList) {
 | 
			
		||||
        return AuthPermissionInfoRespVO.builder()
 | 
			
		||||
 
 | 
			
		||||
@@ -1,18 +1,14 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.convert.auth;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.auth.dto.OAuth2AccessTokenCheckRespDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.session.UserSessionPageItemRespVO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.dataobject.auth.UserSessionDO;
 | 
			
		||||
import org.mapstruct.Mapper;
 | 
			
		||||
import org.mapstruct.factory.Mappers;
 | 
			
		||||
 | 
			
		||||
@Mapper
 | 
			
		||||
public interface UserSessionConvert {
 | 
			
		||||
public interface OAuth2TokenConvert {
 | 
			
		||||
 | 
			
		||||
    UserSessionConvert INSTANCE = Mappers.getMapper(UserSessionConvert.class);
 | 
			
		||||
 | 
			
		||||
    UserSessionPageItemRespVO convert(UserSessionDO session);
 | 
			
		||||
    OAuth2TokenConvert INSTANCE = Mappers.getMapper(OAuth2TokenConvert.class);
 | 
			
		||||
 | 
			
		||||
    OAuth2AccessTokenCheckRespDTO convert(OAuth2AccessTokenDO bean);
 | 
			
		||||
 | 
			
		||||
@@ -1,72 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.dal.dataobject.auth;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
 | 
			
		||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
 | 
			
		||||
import cn.iocoder.yudao.framework.security.core.LoginUser;
 | 
			
		||||
import com.baomidou.mybatisplus.annotation.*;
 | 
			
		||||
import lombok.Builder;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.EqualsAndHashCode;
 | 
			
		||||
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 在线用户表
 | 
			
		||||
 *
 | 
			
		||||
 * 我们已经将 {@link LoginUser} 缓存在 Redis 当中。
 | 
			
		||||
 * 这里额外存储在线用户到 MySQL 中,目的是为了方便管理界面可以灵活查询。
 | 
			
		||||
 * 同时,通过定时轮询 UserSessionDO 表,可以主动删除 Redis 的缓存,因为 Redis 的过期删除是延迟的。
 | 
			
		||||
 *
 | 
			
		||||
 * @author 芋道源码
 | 
			
		||||
 */
 | 
			
		||||
@TableName(value = "system_user_session")
 | 
			
		||||
@KeySequence(value = "system_user_session_seq")
 | 
			
		||||
@Data
 | 
			
		||||
@Builder
 | 
			
		||||
@EqualsAndHashCode(callSuper = true)
 | 
			
		||||
@Deprecated
 | 
			
		||||
public class UserSessionDO extends BaseDO {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 会话编号
 | 
			
		||||
     */
 | 
			
		||||
    private Long id;
 | 
			
		||||
    /**
 | 
			
		||||
     * 令牌
 | 
			
		||||
     */
 | 
			
		||||
    private String token;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 用户编号
 | 
			
		||||
     *
 | 
			
		||||
     * 关联 AdminUserDO.id 或者 MemberUserDO.id
 | 
			
		||||
     */
 | 
			
		||||
    private Long userId;
 | 
			
		||||
    /**
 | 
			
		||||
     * 用户类型
 | 
			
		||||
     *
 | 
			
		||||
     * 枚举 {@link UserTypeEnum}
 | 
			
		||||
     */
 | 
			
		||||
    private Integer userType;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 用户账号
 | 
			
		||||
     *
 | 
			
		||||
     * 冗余,因为账号可以变更
 | 
			
		||||
     */
 | 
			
		||||
    private String username;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 用户 IP
 | 
			
		||||
     */
 | 
			
		||||
    private String userIp;
 | 
			
		||||
    /**
 | 
			
		||||
     * 浏览器 UA
 | 
			
		||||
     */
 | 
			
		||||
    private String userAgent;
 | 
			
		||||
    /**
 | 
			
		||||
     * 会话超时时间
 | 
			
		||||
     */
 | 
			
		||||
    private Date sessionTimeout;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,37 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.dal.mysql.auth;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
 | 
			
		||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 | 
			
		||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 | 
			
		||||
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.session.UserSessionPageReqVO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.dataobject.auth.UserSessionDO;
 | 
			
		||||
import org.apache.ibatis.annotations.Mapper;
 | 
			
		||||
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
@Mapper
 | 
			
		||||
public interface UserSessionMapper extends BaseMapperX<UserSessionDO> {
 | 
			
		||||
 | 
			
		||||
    default PageResult<UserSessionDO> selectPage(UserSessionPageReqVO reqVO, Collection<Long> userIds) {
 | 
			
		||||
        return selectPage(reqVO, new LambdaQueryWrapperX<UserSessionDO>()
 | 
			
		||||
                .inIfPresent(UserSessionDO::getUserId, userIds)
 | 
			
		||||
                .likeIfPresent(UserSessionDO::getUserIp, reqVO.getUserIp()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    default List<UserSessionDO> selectListBySessionTimoutLt() {
 | 
			
		||||
        return selectList(new LambdaQueryWrapperX<UserSessionDO>()
 | 
			
		||||
                .lt(UserSessionDO::getSessionTimeout, new Date()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    default void updateByToken(String token, UserSessionDO updateObj) {
 | 
			
		||||
        update(updateObj, new LambdaQueryWrapperX<UserSessionDO>()
 | 
			
		||||
                .eq(UserSessionDO::getToken, token));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    default void deleteByToken(String token) {
 | 
			
		||||
        delete(new LambdaQueryWrapperX<UserSessionDO>().eq(UserSessionDO::getToken, token));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.dal.redis;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine;
 | 
			
		||||
import cn.iocoder.yudao.framework.security.core.LoginUser;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO;
 | 
			
		||||
 | 
			
		||||
import java.time.Duration;
 | 
			
		||||
@@ -19,10 +18,6 @@ public interface RedisKeyConstants {
 | 
			
		||||
            "captcha_code:%s", // 参数为 uuid
 | 
			
		||||
            STRING, String.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC);
 | 
			
		||||
 | 
			
		||||
    RedisKeyDefine LOGIN_USER = new RedisKeyDefine("登录用户的缓存",
 | 
			
		||||
            "login_user:%s", // 参数为 token 令牌
 | 
			
		||||
            STRING, LoginUser.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC);
 | 
			
		||||
 | 
			
		||||
    RedisKeyDefine OAUTH2_ACCESS_TOKEN = new RedisKeyDefine("访问令牌的缓存",
 | 
			
		||||
            "oauth2_access_token:%s", // 参数为访问令牌 token
 | 
			
		||||
            STRING, OAuth2AccessTokenDO.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,52 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.dal.redis.auth;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
 | 
			
		||||
import cn.iocoder.yudao.framework.security.config.SecurityProperties;
 | 
			
		||||
import cn.iocoder.yudao.framework.security.core.LoginUser;
 | 
			
		||||
import org.springframework.data.redis.core.StringRedisTemplate;
 | 
			
		||||
import org.springframework.stereotype.Repository;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Resource;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants.LOGIN_USER;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * {@link LoginUser} 的 RedisDAO
 | 
			
		||||
 *
 | 
			
		||||
 * @author 芋道源码
 | 
			
		||||
 */
 | 
			
		||||
@Repository
 | 
			
		||||
public class LoginUserRedisDAO {
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private StringRedisTemplate stringRedisTemplate;
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private SecurityProperties securityProperties;
 | 
			
		||||
 | 
			
		||||
    public LoginUser get(String token) {
 | 
			
		||||
        String redisKey = formatKey(token);
 | 
			
		||||
        return JsonUtils.parseObject(stringRedisTemplate.opsForValue().get(redisKey), LoginUser.class);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Boolean exists(String token) {
 | 
			
		||||
        String redisKey = formatKey(token);
 | 
			
		||||
        return stringRedisTemplate.hasKey(redisKey);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void set(String token, LoginUser loginUser) {
 | 
			
		||||
        String redisKey = formatKey(token);
 | 
			
		||||
        stringRedisTemplate.opsForValue().set(redisKey, JsonUtils.toJsonString(loginUser),
 | 
			
		||||
                securityProperties.getSessionTimeout());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void delete(String token) {
 | 
			
		||||
        String redisKey = formatKey(token);
 | 
			
		||||
        stringRedisTemplate.delete(redisKey);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static String formatKey(String token) {
 | 
			
		||||
        return LOGIN_USER.formatKey(token);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -17,9 +17,9 @@ public interface AdminAuthService {
 | 
			
		||||
     * 账号登录
 | 
			
		||||
     *
 | 
			
		||||
     * @param reqVO 登录信息
 | 
			
		||||
     * @return 身份令牌,使用 JWT 方式
 | 
			
		||||
     * @return 登录结果
 | 
			
		||||
     */
 | 
			
		||||
    String login(@Valid AuthLoginReqVO reqVO);
 | 
			
		||||
    AuthLoginRespVO login(@Valid AuthLoginReqVO reqVO);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 基于 token 退出登录
 | 
			
		||||
@@ -39,26 +39,24 @@ public interface AdminAuthService {
 | 
			
		||||
     * 短信登录
 | 
			
		||||
     *
 | 
			
		||||
     * @param reqVO 登录信息
 | 
			
		||||
     * @return 身份令牌,使用 JWT 方式
 | 
			
		||||
     * @return 登录结果
 | 
			
		||||
     */
 | 
			
		||||
    String smsLogin(AuthSmsLoginReqVO reqVO) ;
 | 
			
		||||
    AuthLoginRespVO smsLogin(AuthSmsLoginReqVO reqVO) ;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 社交快捷登录,使用 code 授权码
 | 
			
		||||
     *
 | 
			
		||||
     * @param reqVO 登录信息
 | 
			
		||||
     * @return 身份令牌,使用 JWT 方式
 | 
			
		||||
     * @return 登录结果
 | 
			
		||||
     */
 | 
			
		||||
    String socialQuickLogin(@Valid AuthSocialQuickLoginReqVO reqVO);
 | 
			
		||||
    AuthLoginRespVO socialQuickLogin(@Valid AuthSocialQuickLoginReqVO reqVO);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 社交绑定登录,使用 code 授权码 + 账号密码
 | 
			
		||||
     *
 | 
			
		||||
     * @param reqVO 登录信息
 | 
			
		||||
     * @param userIp 用户 IP
 | 
			
		||||
     * @param userAgent 用户 UA
 | 
			
		||||
     * @return 身份令牌,使用 JWT 方式
 | 
			
		||||
     * @return 登录结果
 | 
			
		||||
     */
 | 
			
		||||
    String socialBindLogin(@Valid AuthSocialBindLoginReqVO reqVO);
 | 
			
		||||
    AuthLoginRespVO socialBindLogin(@Valid AuthSocialBindLoginReqVO reqVO);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@ import cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth.*;
 | 
			
		||||
import cn.iocoder.yudao.module.system.convert.auth.AuthConvert;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.dataobject.auth.OAuth2AccessTokenDO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.enums.auth.OAuth2ClientIdEnum;
 | 
			
		||||
import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum;
 | 
			
		||||
import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum;
 | 
			
		||||
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
 | 
			
		||||
@@ -58,7 +59,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
 | 
			
		||||
    private SmsCodeApi smsCodeApi;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String login(AuthLoginReqVO reqVO) {
 | 
			
		||||
    public AuthLoginRespVO login(AuthLoginReqVO reqVO) {
 | 
			
		||||
        // 判断验证码是否正确
 | 
			
		||||
        verifyCaptcha(reqVO);
 | 
			
		||||
 | 
			
		||||
@@ -80,7 +81,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String smsLogin(AuthSmsLoginReqVO reqVO) {
 | 
			
		||||
    public AuthLoginRespVO smsLogin(AuthSmsLoginReqVO reqVO) {
 | 
			
		||||
        // 校验验证码
 | 
			
		||||
        smsCodeApi.useSmsCode(AuthConvert.INSTANCE.convert(reqVO, SmsSceneEnum.ADMIN_MEMBER_LOGIN.getScene(), getClientIP()));
 | 
			
		||||
 | 
			
		||||
@@ -161,7 +162,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String socialQuickLogin(AuthSocialQuickLoginReqVO reqVO) {
 | 
			
		||||
    public AuthLoginRespVO socialQuickLogin(AuthSocialQuickLoginReqVO reqVO) {
 | 
			
		||||
        // 使用 code 授权码,进行登录。然后,获得到绑定的用户编号
 | 
			
		||||
        Long userId = socialUserService.getBindUserId(UserTypeEnum.ADMIN.getValue(), reqVO.getType(),
 | 
			
		||||
                reqVO.getCode(), reqVO.getState());
 | 
			
		||||
@@ -180,7 +181,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String socialBindLogin(AuthSocialBindLoginReqVO reqVO) {
 | 
			
		||||
    public AuthLoginRespVO socialBindLogin(AuthSocialBindLoginReqVO reqVO) {
 | 
			
		||||
        // 使用账号密码,进行登录。
 | 
			
		||||
        AdminUserDO user = login0(reqVO.getUsername(), reqVO.getPassword());
 | 
			
		||||
 | 
			
		||||
@@ -191,13 +192,14 @@ public class AdminAuthServiceImpl implements AdminAuthService {
 | 
			
		||||
        return createTokenAfterLoginSuccess(user.getId(), reqVO.getUsername(), LoginLogTypeEnum.LOGIN_SOCIAL);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private String createTokenAfterLoginSuccess(Long userId, String username, LoginLogTypeEnum logType) {
 | 
			
		||||
    private AuthLoginRespVO createTokenAfterLoginSuccess(Long userId, String username, LoginLogTypeEnum logType) {
 | 
			
		||||
        // 插入登陆日志
 | 
			
		||||
        createLoginLog(userId, username, logType, LoginResultEnum.SUCCESS);
 | 
			
		||||
        // 创建访问令牌
 | 
			
		||||
        // TODO clientId
 | 
			
		||||
        return oauth2TokenService.createAccessToken(userId, getUserType().getValue(), 1L)
 | 
			
		||||
                .getAccessToken();
 | 
			
		||||
        OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.createAccessToken(userId, getUserType().getValue(),
 | 
			
		||||
                OAuth2ClientIdEnum.DEFAULT.getId());
 | 
			
		||||
        // 构建返回结果
 | 
			
		||||
        return AuthConvert.INSTANCE.convert(accessTokenDO);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
 
 | 
			
		||||
@@ -1,36 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.service.auth;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
 | 
			
		||||
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.session.UserSessionPageReqVO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.dataobject.auth.UserSessionDO;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 在线用户 Session Service 接口
 | 
			
		||||
 *
 | 
			
		||||
 * @author 芋道源码
 | 
			
		||||
 */
 | 
			
		||||
public interface UserSessionService {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获得在线用户分页列表
 | 
			
		||||
     *
 | 
			
		||||
     * @param reqVO 分页条件
 | 
			
		||||
     * @return 份额与列表
 | 
			
		||||
     */
 | 
			
		||||
    PageResult<UserSessionDO> getUserSessionPage(UserSessionPageReqVO reqVO);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 删除在线用户 Session
 | 
			
		||||
     *
 | 
			
		||||
     * @param token token 令牌
 | 
			
		||||
     */
 | 
			
		||||
    void deleteUserSession(String token);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 删除在线用户 Session
 | 
			
		||||
     *
 | 
			
		||||
     * @param id 编号
 | 
			
		||||
     */
 | 
			
		||||
    void deleteUserSession(Long id);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,98 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.service.auth;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.collection.CollUtil;
 | 
			
		||||
import cn.hutool.core.util.StrUtil;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
 | 
			
		||||
import cn.iocoder.yudao.framework.security.config.SecurityProperties;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.session.UserSessionPageReqVO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.dataobject.auth.UserSessionDO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.mysql.auth.UserSessionMapper;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.redis.auth.LoginUserRedisDAO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum;
 | 
			
		||||
import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum;
 | 
			
		||||
import cn.iocoder.yudao.module.system.service.logger.LoginLogService;
 | 
			
		||||
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Resource;
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 在线用户 Session Service 实现类
 | 
			
		||||
 *
 | 
			
		||||
 * @author 芋道源码
 | 
			
		||||
 */
 | 
			
		||||
@Slf4j
 | 
			
		||||
@Service
 | 
			
		||||
public class UserSessionServiceImpl implements UserSessionService {
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private UserSessionMapper userSessionMapper;
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private AdminUserService userService;
 | 
			
		||||
    @Resource
 | 
			
		||||
    private LoginLogService loginLogService;
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private LoginUserRedisDAO loginUserRedisDAO;
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private SecurityProperties securityProperties;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public PageResult<UserSessionDO> getUserSessionPage(UserSessionPageReqVO reqVO) {
 | 
			
		||||
        // 处理基于用户昵称的查询
 | 
			
		||||
        Collection<Long> userIds = null;
 | 
			
		||||
        if (StrUtil.isNotEmpty(reqVO.getUsername())) {
 | 
			
		||||
            userIds = convertSet(userService.getUsersByUsername(reqVO.getUsername()), AdminUserDO::getId);
 | 
			
		||||
            if (CollUtil.isEmpty(userIds)) {
 | 
			
		||||
                return PageResult.empty();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return userSessionMapper.selectPage(reqVO, userIds);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void createLogoutLog(UserSessionDO session, LoginLogTypeEnum type) {
 | 
			
		||||
        LoginLogCreateReqDTO reqDTO = new LoginLogCreateReqDTO();
 | 
			
		||||
        reqDTO.setLogType(type.getType());
 | 
			
		||||
        reqDTO.setTraceId(TracerUtils.getTraceId());
 | 
			
		||||
        reqDTO.setUserId(session.getUserId());
 | 
			
		||||
        reqDTO.setUserType(session.getUserType());
 | 
			
		||||
        reqDTO.setUsername(session.getUsername());
 | 
			
		||||
        reqDTO.setUserAgent(session.getUserAgent());
 | 
			
		||||
        reqDTO.setUserIp(session.getUserIp());
 | 
			
		||||
        reqDTO.setResult(LoginResultEnum.SUCCESS.getResult());
 | 
			
		||||
        loginLogService.createLoginLog(reqDTO);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void deleteUserSession(String token) {
 | 
			
		||||
        // 删除 Redis 缓存
 | 
			
		||||
        loginUserRedisDAO.delete(token);
 | 
			
		||||
        // 删除 DB 记录
 | 
			
		||||
        userSessionMapper.deleteByToken(token);
 | 
			
		||||
        // 无需记录日志,因为退出那已经记录
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void deleteUserSession(Long id) {
 | 
			
		||||
        UserSessionDO session = userSessionMapper.selectById(id);
 | 
			
		||||
        if (session == null) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        // 删除 Redis 缓存
 | 
			
		||||
        loginUserRedisDAO.delete(session.getToken());
 | 
			
		||||
        // 删除 DB 记录
 | 
			
		||||
        userSessionMapper.deleteById(id);
 | 
			
		||||
        // 记录退出日志
 | 
			
		||||
        createLogoutLog(session, LoginLogTypeEnum.LOGOUT_DELETE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user