264 lines
11 KiB
Java
264 lines
11 KiB
Java
|
|
package com.xjrsoft.auth.controller;
|
|||
|
|
|
|||
|
|
import cn.dev33.satoken.SaManager;
|
|||
|
|
import cn.dev33.satoken.config.SaTokenConfig;
|
|||
|
|
import cn.dev33.satoken.session.SaSession;
|
|||
|
|
import cn.dev33.satoken.stp.SaLoginModel;
|
|||
|
|
import cn.dev33.satoken.stp.StpUtil;
|
|||
|
|
import cn.hutool.core.util.StrUtil;
|
|||
|
|
import cn.hutool.jwt.JWT;
|
|||
|
|
import cn.hutool.jwt.JWTUtil;
|
|||
|
|
import com.baomidou.mybatisplus.core.toolkit.StringPool;
|
|||
|
|
import com.xjrsoft.auth.dto.LoginDto;
|
|||
|
|
import com.xjrsoft.auth.service.ILoginService;
|
|||
|
|
import com.xjrsoft.auth.service.SsoService;
|
|||
|
|
import com.xjrsoft.common.core.annotation.XjrLog;
|
|||
|
|
import com.xjrsoft.common.core.config.KeyCloakConfig;
|
|||
|
|
import com.xjrsoft.common.core.config.XjrSmsConfig;
|
|||
|
|
import com.xjrsoft.common.core.constant.GlobalConstant;
|
|||
|
|
import com.xjrsoft.common.core.domain.result.R;
|
|||
|
|
import com.xjrsoft.common.core.enums.EnabledMark;
|
|||
|
|
import com.xjrsoft.common.core.enums.YesOrNoEnum;
|
|||
|
|
import com.xjrsoft.common.core.exception.MyException;
|
|||
|
|
import com.xjrsoft.common.core.uitls.SmsSender;
|
|||
|
|
import com.xjrsoft.common.redis.service.RedisUtil;
|
|||
|
|
import com.xjrsoft.organization.client.IOauthClient;
|
|||
|
|
import com.xjrsoft.organization.client.IUserClient;
|
|||
|
|
import com.xjrsoft.organization.entity.User;
|
|||
|
|
import com.xjrsoft.system.client.ILoginConfigClient;
|
|||
|
|
import com.xjrsoft.system.dto.*;
|
|||
|
|
import com.xjrsoft.system.entity.LoginConfig;
|
|||
|
|
import io.swagger.v3.oas.annotations.Operation;
|
|||
|
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
|||
|
|
import lombok.RequiredArgsConstructor;
|
|||
|
|
import me.zhyd.oauth.request.AuthRequest;
|
|||
|
|
import me.zhyd.oauth.utils.AuthStateUtils;
|
|||
|
|
import org.apache.commons.lang3.RandomUtils;
|
|||
|
|
import org.apache.commons.lang3.StringUtils;
|
|||
|
|
import org.apache.commons.lang3.math.NumberUtils;
|
|||
|
|
import org.keycloak.authorization.client.AuthzClient;
|
|||
|
|
import org.keycloak.authorization.client.Configuration;
|
|||
|
|
import org.keycloak.representations.AccessTokenResponse;
|
|||
|
|
import org.springframework.web.bind.annotation.*;
|
|||
|
|
|
|||
|
|
import javax.validation.Valid;
|
|||
|
|
import java.util.HashMap;
|
|||
|
|
import java.util.List;
|
|||
|
|
import java.util.Map;
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @Author: tzx
|
|||
|
|
* @Date: 2023/10/12 15:39
|
|||
|
|
*/
|
|||
|
|
@RestController
|
|||
|
|
@Tag(name = "登录模块")
|
|||
|
|
@RequestMapping(GlobalConstant.SYSTEM_MODULE_PREFIX)
|
|||
|
|
@RequiredArgsConstructor
|
|||
|
|
public class LoginController {
|
|||
|
|
|
|||
|
|
private final ILoginService loginService;
|
|||
|
|
|
|||
|
|
private final IUserClient userClient;
|
|||
|
|
|
|||
|
|
private final RedisUtil redisUtil;
|
|||
|
|
|
|||
|
|
private KeyCloakConfig keyCloakConfig;
|
|||
|
|
|
|||
|
|
private SmsSender smsSender;
|
|||
|
|
|
|||
|
|
private XjrSmsConfig smsConfig;
|
|||
|
|
|
|||
|
|
private IOauthClient oauthClient;
|
|||
|
|
|
|||
|
|
private final ILoginConfigClient loginConfigClient;
|
|||
|
|
|
|||
|
|
private SsoService ssoService;
|
|||
|
|
|
|||
|
|
|
|||
|
|
@PostMapping(value = {"/login/{ltpasToken}", "/login"})
|
|||
|
|
@Operation(summary = "登录", description = "传入账号:account,密码:password")
|
|||
|
|
@XjrLog(value = "账号密码登录成功")
|
|||
|
|
public R login(@RequestBody @Valid LoginDto dto, @PathVariable(required = false) String ltpasToken) {
|
|||
|
|
if(StrUtil.isNotBlank (ltpasToken)) {
|
|||
|
|
String userName = ssoService.auth(ltpasToken);
|
|||
|
|
if(StrUtil.isNotBlank(userName)) {
|
|||
|
|
dto.setUserName(userName);
|
|||
|
|
User user = loginService.getUserInfoByName(userName);
|
|||
|
|
dto.setPassword(user.getPassword());
|
|||
|
|
return R.ok(loginService.login(dto));
|
|||
|
|
} else {
|
|||
|
|
return R.error("秘钥登录失败");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return R.ok(loginService.login(dto));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@PostMapping("/create-token")
|
|||
|
|
@Operation(summary = "创建token", description = "传入账号:account,密码:password")
|
|||
|
|
@XjrLog(value = "账号密码登录成功")
|
|||
|
|
public R createToken(@RequestBody @Valid CreateTokenDto dto) {
|
|||
|
|
return R.ok(loginService.createToken(dto));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 发送验证码
|
|||
|
|
*/
|
|||
|
|
@GetMapping("/captcha")
|
|||
|
|
@XjrLog(value = "发送验证码")
|
|||
|
|
@Operation(summary = "发送验证码", description = "传入账号:mobile")
|
|||
|
|
public R captcha(@RequestParam String mobile) {
|
|||
|
|
// 验证短信限时发送次数验证
|
|||
|
|
// 获取该号码短信的发送次数
|
|||
|
|
Object o = redisUtil.get(GlobalConstant.CACHE_COUNT_SMS_CODE_PREFIX + mobile);
|
|||
|
|
int sendCount = NumberUtils.toInt(String.valueOf(o));
|
|||
|
|
if (o == null) {
|
|||
|
|
// 未发送过验证码,初始化
|
|||
|
|
redisUtil.set(GlobalConstant.CACHE_COUNT_SMS_CODE_PREFIX + mobile, 1, smsConfig.getLimitTime() * 3600);
|
|||
|
|
} else if (sendCount > smsConfig.getLimitCount()) {
|
|||
|
|
// 发送次数超过限制
|
|||
|
|
return R.error("发送验证码次数达上限,请稍后再试!");
|
|||
|
|
} else {
|
|||
|
|
// 更新发送次数
|
|||
|
|
long expire = redisUtil.getExpire(GlobalConstant.CACHE_COUNT_SMS_CODE_PREFIX + mobile);
|
|||
|
|
redisUtil.set(GlobalConstant.CACHE_COUNT_SMS_CODE_PREFIX + mobile, sendCount + 1, expire);
|
|||
|
|
}
|
|||
|
|
//生成六位数的字符串
|
|||
|
|
String code = RandomUtils.nextInt(100000, 999999) + StringPool.EMPTY;
|
|||
|
|
|
|||
|
|
smsSender.sendCaptcha(mobile, code);
|
|||
|
|
|
|||
|
|
redisUtil.set(GlobalConstant.CAPTCHA + StringPool.UNDERSCORE + mobile, code, 60L);
|
|||
|
|
return R.ok(Boolean.TRUE);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 验证码
|
|||
|
|
*/
|
|||
|
|
@PostMapping("/captcha")
|
|||
|
|
@XjrLog(value = "验证码登录")
|
|||
|
|
public R loginByCaptcha(@RequestBody LoginCaptchaDto loginCaptchaDto) {
|
|||
|
|
String mobile = loginCaptchaDto.getMobile();
|
|||
|
|
String code = redisUtil.get(GlobalConstant.CAPTCHA + StringPool.UNDERSCORE + mobile);
|
|||
|
|
if (code != null && StringUtils.equals(code, loginCaptchaDto.getCode())) {
|
|||
|
|
User user = userClient.getUserByMobileFeign(mobile);
|
|||
|
|
if (user == null) {
|
|||
|
|
return R.error("用户不存在!");
|
|||
|
|
}
|
|||
|
|
if (user.getEnabledMark() == EnabledMark.DISABLED.getCode()) {
|
|||
|
|
return R.error("账户未启用");
|
|||
|
|
}
|
|||
|
|
//此登录接口登录web端
|
|||
|
|
StpUtil.login(user.getId(), "PC");
|
|||
|
|
|
|||
|
|
SaSession tokenSession = StpUtil.getTokenSession();
|
|||
|
|
tokenSession.set(GlobalConstant.LOGIN_USER_INFO_KEY, user);
|
|||
|
|
|
|||
|
|
Map<String, Object> vo = new HashMap<>(1);
|
|||
|
|
vo.put(GlobalConstant.TOKEN_KEY, StpUtil.getTokenValue());
|
|||
|
|
|
|||
|
|
return R.ok(vo);
|
|||
|
|
}
|
|||
|
|
return R.error("验证码不存在!");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 退出
|
|||
|
|
*/
|
|||
|
|
@PostMapping("/logout")
|
|||
|
|
public R logout() {
|
|||
|
|
StpUtil.logout();
|
|||
|
|
return R.ok("登出成功!");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@PostMapping("/token")
|
|||
|
|
@Operation(summary = "根据keycloak-token 登录", description = "传入keycloak-token")
|
|||
|
|
@XjrLog(value = "keycloak-token登录成功")
|
|||
|
|
public R loginByToken(@RequestBody KeyCloakLoginInfoDto dto) {
|
|||
|
|
Map<String, Object> credentialsMap = new HashMap<>(1);
|
|||
|
|
credentialsMap.put("secret", keyCloakConfig.getSecret());
|
|||
|
|
Configuration configuration = new Configuration(keyCloakConfig.getUrl(), keyCloakConfig.getRealm(), keyCloakConfig.getClientId(), credentialsMap, null);
|
|||
|
|
AuthzClient authzClient = AuthzClient.create(configuration);
|
|||
|
|
AccessTokenResponse response = authzClient.obtainAccessToken(keyCloakConfig.getUserName(), keyCloakConfig.getPassword());
|
|||
|
|
|
|||
|
|
if (StrUtil.isNotBlank(response.getError())) {
|
|||
|
|
return R.error(response.getError());
|
|||
|
|
}
|
|||
|
|
//TODO keycloak 登陆过 解析token获取数据 做框架登录操作
|
|||
|
|
JWT jwt = JWTUtil.parseToken(dto.getToken());
|
|||
|
|
Object code = jwt.getPayload(keyCloakConfig.getPayload());
|
|||
|
|
|
|||
|
|
User user = userClient.getUserByCodeFeign(String.valueOf(code));
|
|||
|
|
|
|||
|
|
List<LoginConfig> list = loginConfigClient.getAllListFeign();
|
|||
|
|
if (list.size() == 0){//如果没有,则设置为默认配置,并进行保存
|
|||
|
|
LoginConfig loginConfig = new LoginConfig();
|
|||
|
|
loginConfig.setId(1L);
|
|||
|
|
loginConfig.setMulLogin("0,1");
|
|||
|
|
loginConfig.setMutualExclusion(YesOrNoEnum.YES.getCode());
|
|||
|
|
loginConfig.setWithoutLogin(YesOrNoEnum.YES.getCode());
|
|||
|
|
loginConfig.setPasswordStrategy(YesOrNoEnum.YES.getCode());
|
|||
|
|
loginConfig.setStrategyMaxNumber(7);
|
|||
|
|
list.add(loginConfig);
|
|||
|
|
loginConfigClient.addLoginConfigFeign(loginConfig);
|
|||
|
|
}
|
|||
|
|
LoginConfig loginConfig = list.get(0);
|
|||
|
|
|
|||
|
|
if (user == null) {
|
|||
|
|
return R.error("帐号密码错误!");
|
|||
|
|
} else if (!Integer.valueOf(1).equals(user.getEnabledMark())) {
|
|||
|
|
return R.error("当前账号已被锁定,请联系管理员!");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (StrUtil.isNotBlank(dto.getDevice()) && dto.getDevice() == "PC" && !loginConfig.getMulLogin().contains("0")){
|
|||
|
|
throw new MyException("当前Web端登录未授权,请联系管理员!");
|
|||
|
|
}else if (StrUtil.isNotBlank(dto.getDevice()) && dto.getDevice() == "APP" && !loginConfig.getMulLogin().contains("1")){
|
|||
|
|
throw new MyException("当前APP端登录未授权,请联系管理员!");
|
|||
|
|
}else {
|
|||
|
|
if (StrUtil.isBlank(loginConfig.getMulLogin()) || !loginConfig.getMulLogin().contains("0")){
|
|||
|
|
throw new MyException("当前Web端登录未授权,请联系管理员!");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
SaTokenConfig oldConfig = SaManager.getConfig();
|
|||
|
|
|
|||
|
|
if (loginConfig.getMutualExclusion() == YesOrNoEnum.NO.getCode()){
|
|||
|
|
//不开启同端互斥
|
|||
|
|
oldConfig.setIsConcurrent(true);
|
|||
|
|
}else {
|
|||
|
|
//开启同端互斥
|
|||
|
|
oldConfig.setIsConcurrent(false);
|
|||
|
|
}
|
|||
|
|
// 注入到 SaManager 中
|
|||
|
|
SaManager.setConfig(oldConfig);
|
|||
|
|
|
|||
|
|
if (loginConfig.getWithoutLogin() == YesOrNoEnum.YES.getCode()){//开启就设置为7天免登录
|
|||
|
|
StpUtil.login(user.getId(),new SaLoginModel().setDevice(dto.getDevice()).setTimeout(60 * 60 * 24 * 7));
|
|||
|
|
}else {
|
|||
|
|
//此登录接口登录web端,IsLastingCookie设置为false,也就是关闭浏览器后再次打开需要重新登录
|
|||
|
|
StpUtil.login(user.getId(), new SaLoginModel().setDevice(dto.getDevice()).setIsLastingCookie(false));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
SaSession tokenSession = StpUtil.getTokenSession();
|
|||
|
|
tokenSession.set(GlobalConstant.LOGIN_USER_INFO_KEY, user);
|
|||
|
|
|
|||
|
|
Map<String, Object> vo = new HashMap<>(1);
|
|||
|
|
vo.put(GlobalConstant.TOKEN_KEY, StpUtil.getTokenValue());
|
|||
|
|
|
|||
|
|
return R.ok("登录成功!", vo);
|
|||
|
|
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@PostMapping("/qrcode-login")
|
|||
|
|
@Operation(summary = "oauth 扫码登录", description = "oauth 扫码登录")
|
|||
|
|
@XjrLog(value = "oauth 扫码登录")
|
|||
|
|
public R createAuthorizeUrl(@Valid @RequestBody CreateAuthorizeUrlDto dto){
|
|||
|
|
AuthRequest authRequest = oauthClient.getAuthRequest(dto.getSource());
|
|||
|
|
String authorizeUrl = authRequest.authorize(AuthStateUtils.createState());
|
|||
|
|
return R.ok(authorizeUrl);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|