Pre Merge pull request !116 from dawn9117/satoken

This commit is contained in:
dawn9117 2021-11-27 14:56:10 +00:00 committed by Gitee
commit a1fb33fe95
11 changed files with 358 additions and 105 deletions

View File

@ -10,7 +10,7 @@ import com.ruoyi.common.core.domain.model.LoginBody;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.system.domain.vo.RouterVo;
import com.ruoyi.system.service.ISysMenuService;
import com.ruoyi.system.service.SysLoginService;
import com.ruoyi.system.service.SaUserServices;
import com.ruoyi.system.service.SysPermissionService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@ -38,7 +38,7 @@ import java.util.Set;
@RestController
public class SysLoginController {
private final SysLoginService loginService;
private final SaUserServices userServices;
private final ISysMenuService menuService;
private final SysPermissionService permissionService;
@ -53,8 +53,7 @@ public class SysLoginController {
public AjaxResult<Map<String, Object>> login(@RequestBody LoginBody loginBody) {
Map<String, Object> ajax = new HashMap<>();
// 生成令牌
String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
loginBody.getUuid());
String token = userServices.login(loginBody);
ajax.put(Constants.TOKEN, token);
return AjaxResult.success(ajax);
}

View File

@ -1,10 +1,13 @@
package com.ruoyi.common.core.domain.model;
import com.ruoyi.common.enums.DeviceType;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotNull;
/**
* 用户登录对象
*
@ -16,16 +19,24 @@ import lombok.experimental.Accessors;
@ApiModel("用户登录对象")
public class LoginBody {
/**
* 设备类型
*/
@ApiModelProperty(value = "设备类型(默认pc): pc, app")
private String deviceType = DeviceType.PC.getDevice();
/**
* 用户名
*/
@ApiModelProperty(value = "用户名")
@NotNull(message = "用户名不能为空")
@ApiModelProperty(value = "用户名", required = true)
private String username;
/**
* 用户密码
*/
@ApiModelProperty(value = "用户密码")
@NotNull(message = "用户密码不能为空")
@ApiModelProperty(value = "用户密码", required = true)
private String password;
/**

View File

@ -1,10 +1,13 @@
package com.ruoyi.common.enums;
import com.ruoyi.common.exception.ServiceException;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 设备类型
* 用户类型
* 针对两套 用户体系
*
* @author Lion Li
@ -16,12 +19,27 @@ public enum UserType {
/**
* pc端
*/
SYS_USER("sys_user:"),
SYS_USER("sys_user:", DeviceType.PC),
/**
* app端
*/
APP_USER("app_user:");
APP_USER("app_user:", DeviceType.APP);
/**
* 用户类型
*/
private final String userType;
/**
* 设备类型
*/
private final DeviceType deviceType;
public static UserType getByDeviceType(String deviceType) {
return Arrays.stream(UserType.values())
.filter(type -> type.getDeviceType().getDevice().equalsIgnoreCase(deviceType))
.findFirst()
.orElseThrow(() -> new ServiceException("设备类型不支持:" + deviceType));
}
}

View File

@ -27,25 +27,15 @@ public class LoginUtils {
* 针对一套用户体系
* @param userId 用户id
*/
public static void loginByDevice(Long userId, UserType userType, DeviceType deviceType) {
StpUtil.login(userType.getUserType() + userId, deviceType.getDevice());
public static void loginByDevice(Long userId, UserType userType, String deviceType) {
StpUtil.login(userType.getUserType() + userId, deviceType);
}
/**
* 获取用户id
*/
public static Long getUserId() {
String loginId = StpUtil.getLoginIdAsString();
String userId;
String replace = "";
if (StringUtils.contains(loginId, UserType.SYS_USER.getUserType())) {
userId = StringUtils.replace(loginId, UserType.SYS_USER.getUserType(), replace);
} else if (StringUtils.contains(loginId, UserType.APP_USER.getUserType())){
userId = StringUtils.replace(loginId, UserType.APP_USER.getUserType(), replace);
} else {
throw new UtilException("登录用户: LoginId异常 => " + loginId);
}
return Long.parseLong(userId);
return parseUserId(StpUtil.getLoginIdAsString());
}
/**
@ -56,14 +46,26 @@ public class LoginUtils {
return getUserType(loginId);
}
/**
* 根据登录ID获取用户类型
*
* @param loginId 登录ID
* @return 用户类型
*/
public static UserType getUserType(Object loginId) {
if (StringUtils.contains(loginId.toString(), UserType.SYS_USER.getUserType())) {
return UserType.SYS_USER;
} else if (StringUtils.contains(loginId.toString(), UserType.APP_USER.getUserType())){
return UserType.APP_USER;
} else {
throw new UtilException("登录用户: LoginId异常 => " + loginId);
for (UserType userType : UserType.values()) {
if (StringUtils.startsWith(loginId.toString(), userType.getUserType())) {
return userType;
}
}
throw new UtilException("登录用户: LoginId异常 => " + loginId);
}
/**
* 获取用户ID
*/
public static Long parseUserId(Object loginId) {
UserType userType = getUserType(loginId);
return Long.parseLong(StringUtils.replace(loginId.toString(), userType.getUserType(), StringUtils.EMPTY));
}
}

View File

@ -1,60 +1,33 @@
package com.ruoyi.framework.listener;
package com.ruoyi.system.listener;
import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.listener.SaTokenListener;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.dto.UserOnlineDTO;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.enums.UserType;
import com.ruoyi.common.utils.*;
import com.ruoyi.common.utils.ip.AddressUtils;
import com.ruoyi.common.utils.RedisUtils;
import com.ruoyi.system.service.SaUserServices;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* 用户行为 侦听器的实现
*/
@Component
@Slf4j
@Component
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class UserActionListener implements SaTokenListener {
@Autowired
private SaTokenConfig saTokenConfig;
private final SaUserServices userServices;
/**
* 每次登录时触发
*/
@Override
public void doLogin(String loginType, Object loginId, SaLoginModel loginModel) {
UserType userType = LoginUtils.getUserType(loginId);
if (userType == UserType.SYS_USER) {
UserAgent userAgent = UserAgentUtil.parse(ServletUtils.getRequest().getHeader("User-Agent"));
String ip = ServletUtils.getClientIP();
SysUser user = SecurityUtils.getUser();
String tokenValue = StpUtil.getTokenValue();
UserOnlineDTO userOnlineDTO = new UserOnlineDTO()
.setIpaddr(ip)
.setLoginLocation(AddressUtils.getRealAddressByIP(ip))
.setBrowser(userAgent.getBrowser().getName())
.setOs(userAgent.getOs().getName())
.setLoginTime(System.currentTimeMillis())
.setTokenId(tokenValue)
.setUserName(user.getUserName());
if (StringUtils.isNotNull(user.getDept())) {
userOnlineDTO.setDeptName(user.getDept().getDeptName());
}
RedisUtils.setCacheObject(Constants.ONLINE_TOKEN_KEY + tokenValue, userOnlineDTO, saTokenConfig.getTimeout(), TimeUnit.SECONDS);
log.info("user doLogin, useId:{}, token:{}", loginId, tokenValue);
} else if (userType == UserType.APP_USER) {
// app端 自行根据业务编写
}
userServices.loginSuccess(loginType, loginId, loginModel);
log.info("user doLogin, useId:{}, token:{}", loginId, StpUtil.getTokenValue());
}
/**

View File

@ -0,0 +1,53 @@
package com.ruoyi.system.service;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpInterface;
import com.ruoyi.common.core.domain.model.LoginBody;
import com.ruoyi.common.enums.UserType;
/**
* Sa用户服务接口
*
* @author dawn
*/
public interface ISaUserService extends StpInterface {
/**
* 是否支持
*
* @param userType 用户类型
* @return 是否支持
*/
default boolean isSupport(UserType userType) {
return getUserType().equals(userType);
}
/**
* 获取用户类型
*
* @return UserType
*/
UserType getUserType();
/**
* 用户登录
*
* @param loginBody 登录请求体
* @return token
*/
default String login(LoginBody loginBody) {
throw new UnsupportedOperationException("暂不支持登录, 用户类型:" + getUserType());
}
/**
* 登录成功后调用该接口
*
* @param loginType 登录类型
* @param loginId 登录ID
* @param loginModel 登录模式
*/
default void loginSuccess(String loginType, Object loginId, SaLoginModel loginModel) {
}
}

View File

@ -0,0 +1,86 @@
package com.ruoyi.system.service;
import cn.dev33.satoken.stp.SaLoginModel;
import com.ruoyi.common.core.domain.model.LoginBody;
import com.ruoyi.common.enums.UserType;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.LoginUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 用户服务: 支持多账号体系
*
* @author dawn
*/
@Service
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class SaUserServices {
/**
* 用户服务列表
*/
private final List<ISaUserService> userServices;
/**
* 获取用户权限列表
*
* @param loginId 用户ID
* @param loginType 登录类型
* @return 权限列表
*/
public List<String> getPermissionList(Object loginId, String loginType) {
return getUserService().getPermissionList(loginId, loginType);
}
/**
* 获取用户角色列表
*
* @param loginId 用户ID
* @param loginType 登录类型
* @return 角色列表
*/
public List<String> getRoleList(Object loginId, String loginType) {
return getUserService().getRoleList(loginId, loginType);
}
/**
* 用户给登录
*
* @param loginBody 登录请求体
* @return token
*/
public String login(LoginBody loginBody) {
UserType userType = UserType.getByDeviceType(loginBody.getDeviceType());
return getUserService(userType).login(loginBody);
}
/**
* 登录成功后调用该接口
*
* @param loginType 登录类型
* @param loginId 登录ID
* @param loginModel 登录模式
*/
public void loginSuccess(String loginType, Object loginId, SaLoginModel loginModel) {
getUserService().loginSuccess(loginType, loginId, loginModel);
}
private ISaUserService getUserService() {
return getUserService(LoginUtils.getUserType());
}
private ISaUserService getUserService(UserType userType) {
for (ISaUserService userService : userServices) {
if (userService.isSupport(userType)) {
return userService;
}
}
throw new ServiceException("用户类型不支持:" + userType);
}
}

View File

@ -4,7 +4,6 @@ import cn.dev33.satoken.stp.StpUtil;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.service.LogininforService;
import com.ruoyi.common.enums.DeviceType;
import com.ruoyi.common.enums.UserStatus;
import com.ruoyi.common.enums.UserType;
import com.ruoyi.common.exception.ServiceException;
@ -14,7 +13,6 @@ import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
import com.ruoyi.common.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
@ -46,7 +44,7 @@ public class SysLoginService {
* @param uuid 唯一标识
* @return 结果
*/
public String login(String username, String password, String code, String uuid) {
public String login(String username, String password, String code, String uuid, UserType userType, String deviceType) {
HttpServletRequest request = ServletUtils.getRequest();
boolean captchaOnOff = configService.selectCaptchaOnOff();
// 验证码开关
@ -72,7 +70,7 @@ public class SysLoginService {
asyncService.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"), request);
recordLoginInfo(user.getUserId(), username);
// 生成token
LoginUtils.loginByDevice(user.getUserId(), UserType.SYS_USER, DeviceType.PC);
LoginUtils.loginByDevice(user.getUserId(), userType, deviceType);
return StpUtil.getTokenValue();
}

View File

@ -0,0 +1,42 @@
package com.ruoyi.system.service.impl;
import com.ruoyi.common.core.domain.model.LoginBody;
import com.ruoyi.common.enums.UserType;
import com.ruoyi.system.service.ISaUserService;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* app用户服务
*
* @author dawn
*/
@Service
public class SaAppUserServiceImpl implements ISaUserService {
@Override
public UserType getUserType() {
return UserType.APP_USER;
}
@Override
public List<String> getPermissionList(Object loginId, String loginType) {
// TODO App用户权限获取
throw new UnsupportedOperationException("暂不支持该操作, 用户类型:" + getUserType());
}
@Override
public List<String> getRoleList(Object loginId, String loginType) {
// TODO App用户角色获取
throw new UnsupportedOperationException("暂不支持该操作, 用户类型:" + getUserType());
}
@Override
public String login(LoginBody loginBody) {
// TODO App用户登录
throw new UnsupportedOperationException("暂不支持该操作, 用户类型:" + getUserType());
}
}

View File

@ -1,51 +1,31 @@
package com.ruoyi.system.service.impl;
import cn.dev33.satoken.stp.StpInterface;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.enums.UserType;
import com.ruoyi.common.utils.LoginUtils;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.system.service.SysPermissionService;
import com.ruoyi.system.service.SaUserServices;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@Primary
@Component
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class SaInterfaceImpl implements StpInterface {
@Autowired
private SysPermissionService sysPermissionService;
@Autowired
private ISysUserService iSysUserService;
/**
* 用户服务
*/
private final SaUserServices userServices;
@Override
public List<String> getPermissionList(Object loginId, String loginType) {
UserType userType = LoginUtils.getUserType(loginId);
if (userType == UserType.SYS_USER) {
Long userId = LoginUtils.getUserId();
SysUser user = iSysUserService.getById(userId);
Set<String> menuPermission = sysPermissionService.getMenuPermission(user);
return new ArrayList<>(menuPermission);
} else if (userType == UserType.APP_USER) {
// app端权限返回 自行根据业务编写
}
return new ArrayList<>();
}
@Override
public List<String> getPermissionList(Object loginId, String loginType) {
return userServices.getPermissionList(loginId, loginType);
}
@Override
public List<String> getRoleList(Object loginId, String loginType) {
UserType userType = LoginUtils.getUserType(loginId);
if (userType == UserType.SYS_USER) {
Long userId = LoginUtils.getUserId();
SysUser user = iSysUserService.getById(userId);
Set<String> rolePermission = sysPermissionService.getRolePermission(user);
return new ArrayList<>(rolePermission);
} else if (userType == UserType.APP_USER) {
// app端权限返回 自行根据业务编写
}
return new ArrayList<>();
}
@Override
public List<String> getRoleList(Object loginId, String loginType) {
return userServices.getRoleList(loginId, loginType);
}
}

View File

@ -0,0 +1,91 @@
package com.ruoyi.system.service.impl;
import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.dto.UserOnlineDTO;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginBody;
import com.ruoyi.common.enums.UserType;
import com.ruoyi.common.utils.*;
import com.ruoyi.common.utils.ip.AddressUtils;
import com.ruoyi.system.service.ISaUserService;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.system.service.SysLoginService;
import com.ruoyi.system.service.SysPermissionService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* 系统用户服务
*
* @author dawn
*/
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class SaSysUserServiceImpl implements ISaUserService {
private final ISysUserService sysUserService;
private final SysPermissionService sysPermissionService;
private final SysLoginService loginService;
private final SaTokenConfig saTokenConfig;
@Override
public UserType getUserType() {
return UserType.SYS_USER;
}
@Override
public List<String> getPermissionList(Object loginId, String loginType) {
Long userId = LoginUtils.parseUserId(loginId);
SysUser user = sysUserService.getById(userId);
Set<String> menuPermission = sysPermissionService.getMenuPermission(user);
return new ArrayList<>(menuPermission);
}
@Override
public List<String> getRoleList(Object loginId, String loginType) {
Long userId = LoginUtils.parseUserId(loginId);
SysUser user = sysUserService.getById(userId);
Set<String> rolePermission = sysPermissionService.getRolePermission(user);
return new ArrayList<>(rolePermission);
}
@Override
public String login(LoginBody loginBody) {
return loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
loginBody.getUuid(), getUserType(), loginBody.getDeviceType());
}
@Override
public void loginSuccess(String loginType, Object loginId, SaLoginModel loginModel) {
UserAgent userAgent = UserAgentUtil.parse(ServletUtils.getRequest().getHeader("User-Agent"));
String ip = ServletUtils.getClientIP();
SysUser user = SecurityUtils.getUser();
String tokenValue = StpUtil.getTokenValue();
UserOnlineDTO userOnlineDTO = new UserOnlineDTO()
.setIpaddr(ip)
.setLoginLocation(AddressUtils.getRealAddressByIP(ip))
.setBrowser(userAgent.getBrowser().getName())
.setOs(userAgent.getOs().getName())
.setLoginTime(System.currentTimeMillis())
.setTokenId(tokenValue)
.setUserName(user.getUserName());
if (StringUtils.isNotNull(user.getDept())) {
userOnlineDTO.setDeptName(user.getDept().getDeptName());
}
RedisUtils.setCacheObject(Constants.ONLINE_TOKEN_KEY + tokenValue, userOnlineDTO, saTokenConfig.getTimeout(), TimeUnit.SECONDS);
}
}