package com.xjrsoft.module.system.service.impl; import cn.dev33.satoken.context.SaHolder; import cn.dev33.satoken.oauth2.SaOAuth2Manager; import cn.dev33.satoken.oauth2.config.SaOAuth2Config; import cn.dev33.satoken.secure.BCrypt; import cn.dev33.satoken.session.SaSession; import cn.dev33.satoken.spring.SpringMVCUtil; import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.temp.SaTempUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.StringPool; import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.xjrsoft.common.constant.GlobalConstant; import com.xjrsoft.common.enums.EnabledMark; import com.xjrsoft.common.enums.RoleEnum; import com.xjrsoft.common.exception.MyException; import com.xjrsoft.common.model.result.R; import com.xjrsoft.common.utils.FixedArithmeticCaptcha; import com.xjrsoft.common.utils.RSAUtil; import com.xjrsoft.common.utils.RedisUtil; import com.xjrsoft.common.utils.WeChatUtil; import com.xjrsoft.config.CommonPropertiesConfig; import com.xjrsoft.config.LicenseConfig; import com.xjrsoft.module.organization.entity.*; import com.xjrsoft.module.organization.mapper.UserRoleRelationMapper; import com.xjrsoft.module.organization.service.*; import com.xjrsoft.module.system.dto.CreateTokenDto; import com.xjrsoft.module.system.dto.LoginByCodeDto; import com.xjrsoft.module.system.dto.LoginCaptchaDto; import com.xjrsoft.module.system.dto.LoginDto; import com.xjrsoft.module.system.service.ILoginService; import com.xjrsoft.module.system.vo.CreateTokenVo; import com.xjrsoft.module.system.vo.ImgCaptchaVo; import com.xjrsoft.module.system.vo.LoginByCodeVo; import com.xjrsoft.module.system.vo.LoginVo; import lombok.AllArgsConstructor; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.servlet.http.HttpServletRequest; import java.util.List; import java.util.UUID; import java.util.stream.Collectors; /** * @Author: tzx * @Date: 2023/4/21 14:22 */ @Service @AllArgsConstructor public class LoginServiceImpl implements ILoginService { private final IUserService userService; private final IUserDeptRelationService userDeptRelationService; private final IUserPostRelationService userPostRelationService; private final IPostService postService; private final IDepartmentService departmentService; private final RedisUtil redisUtil; private final LicenseConfig licenseConfig; private final WeChatUtil weChatUtil; private final UserRoleRelationMapper userRoleRelationMapper; @Autowired private CommonPropertiesConfig commonPropertiesConfig; @Override public LoginVo login(LoginDto dto) throws Exception { if (licenseConfig.getEnabled()) { //查出所有在线用户 List onlineUser = StpUtil.searchSessionId("", 0, -1, true); //如果已经登录人数超过授权人数 不允许登录 if (onlineUser.size() >= licenseConfig.getLoginMax()) { throw new MyException("登录人数超过授权人数,无法登录,请联系管理员!"); } } String captchaCode = redisUtil.get(dto.getKey(), 0); if (captchaCode == null) { throw new MyException("验证码已过期,请刷新验证码!"); } if (!captchaCode.equals(dto.getCode())) { throw new MyException("验证码不正确,请刷新验证码!"); } // rsa解密 String decryptData = RSAUtil.decrypt(dto.getPassword()); dto.setPassword(decryptData); LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(User::getUserName, dto.getUserName()); User loginUser = userService.getOne(queryWrapper); // if (loginUser == null || !StrUtil.equals(loginUser.getPassword(), SaSecureUtil.md5BySalt(dto.getPassword(), GlobalConstant.SECRET_KEY))) { // throw new MyException("账号或密码不正确"); // } if (loginUser == null || !BCrypt.checkpw(dto.getPassword(), loginUser.getPassword())) { throw new MyException("账号或密码不正确"); } return getLoginInfo(loginUser, "PC"); } @Override public LoginByCodeVo loginByCode(LoginByCodeDto dto) throws Exception { LoginByCodeVo result = new LoginByCodeVo(); String[] ids = weChatUtil.getOpenid(dto.getCode()); if (ids == null) throw new MyException("code无效"); LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); if (StringUtils.isNotEmpty(ids[1])) { queryWrapper.eq(User::getUnionId, ids[1]); result.setUnionId(ids[1]); } else { queryWrapper.eq(User::getOpenId, ids[0]); result.setOpenid(ids[0]); } User loginUser = userService.getOne(queryWrapper); // result.setOpenid(openId); if (loginUser == null) { return result; } LoginVo loginVo = getLoginInfo(loginUser, "WX-MP"); result.setToken(loginVo.getToken()); result.setUserType(loginVo.getUserType()); return result; } /** * 手机验证码登录 * * @param dto * @return * @throws Exception */ @Override public LoginVo loginByCaptcha(LoginCaptchaDto dto) throws Exception { User user = userService.getOne(Wrappers.lambdaQuery().eq(User::getMobile, dto.getMobile()), false); if (user == null) { throw new MyException("用户不存在!"); } return getLoginInfo(user, "Captcha"); } @Override public CreateTokenVo createToken(CreateTokenDto dto) { CreateTokenVo vo = new CreateTokenVo(); if (dto.getExpire() == -1) { String token = SaTempUtil.createToken(IdUtil.fastSimpleUUID() + StringPool.UNDERSCORE + GlobalConstant.SECRET_KEY, Integer.MAX_VALUE); vo.setToken(token); return vo; } else { String token = SaTempUtil.createToken(IdUtil.fastSimpleUUID() + StringPool.UNDERSCORE + GlobalConstant.SECRET_KEY, dto.getExpire()); vo.setToken(token); return vo; } } /** * 图形验证码 */ @Override public ImgCaptchaVo imgCaptcha() { // 算术类型 FixedArithmeticCaptcha captcha = new FixedArithmeticCaptcha(130, 48); String rKey = GlobalConstant.LOGIN_IMG_CAPTCHA + UUID.randomUUID().toString(); // 存入redis并设置过期时间为30分钟 redisUtil.set(rKey, captcha.text(), 30 * 60); return new ImgCaptchaVo(rKey, captcha.toBase64()); } private LoginVo getLoginInfo(User loginUser, String loginType) throws Exception { LoginVo result = new LoginVo(); if (loginUser.getEnabledMark() == EnabledMark.DISABLED.getCode()) { throw new MyException("账户未启用"); } //此登录接口登录web端 StpUtil.login(loginUser.getId(), loginType); // 获取用户类型(根据固定角色进行匹配) List relations = userRoleRelationMapper.selectList(Wrappers.lambdaQuery(UserRoleRelation.class) .select(UserRoleRelation::getRoleId) .eq(UserRoleRelation::getUserId, StpUtil.getLoginIdAsLong())); result.setUserType(roleMatching(relations)); SaSession tokenSession = StpUtil.getTokenSession(); List userDeptRelations = userDeptRelationService.list(Wrappers.lambdaQuery(UserDeptRelation.class) .eq(UserDeptRelation::getUserId, StpUtil.getLoginIdAsLong())); List userPostRelations = userPostRelationService.list(Wrappers.lambdaQuery(UserPostRelation.class) .eq(UserPostRelation::getUserId, StpUtil.getLoginIdAsLong())); //获取登陆人所选择的身份缓存 String postId = redisUtil.get(GlobalConstant.LOGIN_IDENTITY_CACHE_PREFIX + loginUser.getId()); Post post = new Post(); if (StrUtil.isNotBlank(postId)) { post = postService.getById(postId); } if (userPostRelations.size() > 0) { List postIds = userPostRelations.stream().map(UserPostRelation::getPostId).collect(Collectors.toList()); List postList = postService.listByIds(postIds); if (StrUtil.isBlank(postId) && CollectionUtils.isNotEmpty(postList)) { post = postList.get(0); } tokenSession.set(GlobalConstant.LOGIN_USER_POST_INFO_KEY, post); tokenSession.set(GlobalConstant.LOGIN_USER_POST_LIST_KEY, postList); loginUser.setPostId(post.getId()); //将登陆人所选择的身份缓存起来 //切换身份的时候 会一起修改 redisUtil.set(GlobalConstant.LOGIN_IDENTITY_CACHE_PREFIX + loginUser.getId(), post.getId()); } if (userDeptRelations.size() > 0) { // 存当前用户所有部门到缓存 List departmentIds = userDeptRelations.stream().map(UserDeptRelation::getDeptId).collect(Collectors.toList()); List departmentList = departmentService.listByIds(departmentIds); tokenSession.set(GlobalConstant.LOGIN_USER_DEPT_LIST_KEY, departmentList); //如果此人有岗位 使用岗位的deptId 找到当前组织机构 if (ObjectUtil.isNotNull(post.getId())) { Department department = departmentService.getById(post.getDeptId()); tokenSession.set(GlobalConstant.LOGIN_USER_DEPT_INFO_KEY, department); loginUser.setDepartmentId(department.getId()); } else { if (departmentList.size() > 0) { Department department = departmentList.get(0); tokenSession.set(GlobalConstant.LOGIN_USER_DEPT_INFO_KEY, department); loginUser.setDepartmentId(department.getId()); } } } //根据登录信息 将post 和 department 信息存入用户信息中 tokenSession.set(GlobalConstant.LOGIN_USER_INFO_KEY, loginUser); result.setToken(StpUtil.getTokenValue()); // 判断是不是OAuth2 String oauth2Info = SaHolder.getRequest().getCookieValue("Oauth2Info"); if (oauth2Info != null) { result.setRedirectUri(redisUtil.get(oauth2Info)); } return result; } /** * 角色匹配 * * @return */ private Long roleMatching(List relations) { for (UserRoleRelation role : relations) { if (role.getRoleId() == RoleEnum.PARENT.getCode()) { return RoleEnum.PARENT.getCode(); } if (role.getRoleId() == RoleEnum.TEACHER.getCode()) { return RoleEnum.TEACHER.getCode(); } if (role.getRoleId() == RoleEnum.STUDENT.getCode()) { return RoleEnum.STUDENT.getCode(); } if (role.getRoleId() == RoleEnum.ADMIN.getCode()) { return RoleEnum.ADMIN.getCode(); } } return 0L; } }