|
|
@@ -2,15 +2,24 @@ package org.dromara.auth.service;
|
|
|
|
|
|
import cn.dev33.satoken.exception.NotLoginException;
|
|
|
import cn.dev33.satoken.secure.BCrypt;
|
|
|
+import cn.dev33.satoken.stp.SaLoginModel;
|
|
|
import cn.dev33.satoken.stp.StpUtil;
|
|
|
import cn.hutool.core.bean.BeanUtil;
|
|
|
+import cn.hutool.core.codec.Base64;
|
|
|
import cn.hutool.core.collection.CollUtil;
|
|
|
import cn.hutool.core.util.ObjectUtil;
|
|
|
+import cn.hutool.core.util.StrUtil;
|
|
|
+import cn.hutool.http.HttpRequest;
|
|
|
+import cn.hutool.http.HttpUtil;
|
|
|
+import cn.hutool.json.JSONObject;
|
|
|
+import cn.hutool.json.JSONUtil;
|
|
|
import com.baomidou.lock.annotation.Lock4j;
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import me.zhyd.oauth.model.AuthUser;
|
|
|
import org.apache.dubbo.config.annotation.DubboReference;
|
|
|
+import org.dromara.auth.config.WechatConfig;
|
|
|
+import org.dromara.auth.domain.vo.LoginVo;
|
|
|
import org.dromara.auth.form.RegisterBody;
|
|
|
import org.dromara.auth.properties.CaptchaProperties;
|
|
|
import org.dromara.auth.properties.UserPasswordProperties;
|
|
|
@@ -39,13 +48,19 @@ import org.dromara.system.api.domain.bo.RemoteSocialBo;
|
|
|
import org.dromara.system.api.domain.bo.RemoteUserBo;
|
|
|
import org.dromara.system.api.domain.vo.RemoteSocialVo;
|
|
|
import org.dromara.system.api.domain.vo.RemoteTenantVo;
|
|
|
+import org.dromara.system.api.domain.vo.RemoteUserVo;
|
|
|
import org.dromara.system.api.model.LoginUser;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
+import java.io.UnsupportedEncodingException;
|
|
|
+import java.net.URLEncoder;
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
import java.time.Duration;
|
|
|
import java.util.Date;
|
|
|
+import java.util.HashMap;
|
|
|
import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
import java.util.function.Supplier;
|
|
|
|
|
|
/**
|
|
|
@@ -70,6 +85,9 @@ public class SysLoginService {
|
|
|
@Autowired
|
|
|
private final CaptchaProperties captchaProperties;
|
|
|
|
|
|
+ @Autowired
|
|
|
+ private WechatConfig wechatConfig;
|
|
|
+
|
|
|
/**
|
|
|
* 绑定第三方用户
|
|
|
*
|
|
|
@@ -265,4 +283,134 @@ public class SysLoginService {
|
|
|
throw new TenantException("tenant.expired");
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ *
|
|
|
+ * @param code
|
|
|
+ * @param otherInfo 回调地址的类型
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ //业务中台的单点登录
|
|
|
+ public LoginVo codeLogin(String code,String otherInfo) {
|
|
|
+ String redirectUri = wechatConfig.getDomainName() + wechatConfig.getContextPath() + "#/";
|
|
|
+ if("home".equals(otherInfo) || "school_code".equals(otherInfo)){
|
|
|
+ redirectUri += otherInfo;
|
|
|
+ }else{
|
|
|
+ throw new ServiceException("参数有误!");
|
|
|
+ }
|
|
|
+
|
|
|
+ boolean isTest = true; // 是否模拟单点登陆为正常结果,仅测试时为true
|
|
|
+ Map<String, String> loginInfo = new HashMap<>(2);
|
|
|
+ if(!isTest){
|
|
|
+ // code 换取 token
|
|
|
+ String access_token = null;
|
|
|
+ try {
|
|
|
+ access_token = getAccessToken(code, redirectUri);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("单点登录异常:{}", e.getMessage());
|
|
|
+ throw new ServiceException("单点登录异常!");
|
|
|
+ }
|
|
|
+ // token 换取用户信息
|
|
|
+ loginInfo = getLoginUser(access_token);
|
|
|
+ }else{
|
|
|
+ loginInfo.put("ssoId", "00327B1BFA2A69140E1902F23597729759A");
|
|
|
+ loginInfo.put("openId", "13602");
|
|
|
+ }
|
|
|
+
|
|
|
+ String openId = loginInfo.get("openId");
|
|
|
+ String ssoId = loginInfo.get("ssoId");
|
|
|
+
|
|
|
+ // 根据otherSysId获取用户信息
|
|
|
+ RemoteUserVo remoteUserVo = remoteUserService.selectUserVoByOtherId(ssoId);
|
|
|
+ if (remoteUserVo == null) {
|
|
|
+ log.error("一卡通无此人员信息,ssoId:{},openId: {}", ssoId, openId);
|
|
|
+ throw new ServiceException(String.format("一卡通无此人员信息,ssoId:%s,openId: %s", ssoId, openId));
|
|
|
+ }
|
|
|
+ // 登陆
|
|
|
+ // 构建loginUser
|
|
|
+ LoginUser loginUser = new LoginUser();
|
|
|
+ BeanUtil.copyProperties(remoteUserVo, loginUser);
|
|
|
+ loginUser.setClientKey("app");
|
|
|
+ loginUser.setDeviceType("android");
|
|
|
+
|
|
|
+ SaLoginModel model = new SaLoginModel();
|
|
|
+ model.setDevice("android");
|
|
|
+ // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置
|
|
|
+ // 例如: 后台用户30分钟过期 app用户1天过期
|
|
|
+ model.setTimeout(604800); // 1天
|
|
|
+ model.setActiveTimeout(3600); //默认1小时
|
|
|
+ model.setExtra(LoginHelper.CLIENT_KEY, "428a8310cd442757ae699df5d894f051");
|
|
|
+ // 生成token
|
|
|
+ LoginHelper.login(loginUser, model);
|
|
|
+
|
|
|
+ LoginVo loginVo = new LoginVo();
|
|
|
+ loginVo.setAccessToken(StpUtil.getTokenValue());
|
|
|
+ loginVo.setExpireIn(StpUtil.getTokenTimeout());
|
|
|
+ loginVo.setClientId("428a8310cd442757ae699df5d894f051");
|
|
|
+ loginVo.setOpenid(Base64.encode(openId, StandardCharsets.UTF_8));
|
|
|
+ loginVo.setOtherSysId(ssoId);
|
|
|
+ log.info("单点登录成功 otherSysId:{}, userName:{}", ssoId, remoteUserVo.getUserName());
|
|
|
+ return loginVo;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取token
|
|
|
+ * @param code
|
|
|
+ * @param redirectUri
|
|
|
+ * @return
|
|
|
+ * @throws UnsupportedEncodingException
|
|
|
+ */
|
|
|
+ public String getAccessToken(String code, String redirectUri) throws UnsupportedEncodingException {
|
|
|
+ // 获取token的地址
|
|
|
+ String interface_url = wechatConfig.getPortUrl() + "prod-api/system/oauth2/token/get";
|
|
|
+
|
|
|
+ interface_url += "?client_id=" + wechatConfig.getClientId();
|
|
|
+ interface_url += "&client_secret=" + wechatConfig.getClientSecret();
|
|
|
+ interface_url += "&grant_type=authorization_code";
|
|
|
+ interface_url += "&code=" + code;
|
|
|
+ interface_url += "&redirect_uri=" + URLEncoder.encode(redirectUri, StandardCharsets.UTF_8);
|
|
|
+
|
|
|
+ log.info("token获取地址:{}", interface_url);
|
|
|
+
|
|
|
+ String access_token = HttpUtil.createPost(interface_url).execute().body();
|
|
|
+ String access_token_json = JSONUtil.parseObj(access_token).getStr("data");
|
|
|
+ access_token = JSONUtil.parseObj(access_token_json).getStr("access_token");
|
|
|
+ if (StrUtil.isNotEmpty(access_token)) {
|
|
|
+ return access_token;
|
|
|
+ } else {
|
|
|
+ log.info("获取token失败,code:{},业务域名:{}", code, interface_url);
|
|
|
+ throw new ServiceException(String.format("获取token失败,code:%s,业务域名:%s", code, interface_url));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取用户信息
|
|
|
+ * @param token
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public Map<String, String> getLoginUser(String token) {
|
|
|
+ String openId = "";
|
|
|
+ String ssoId = "";
|
|
|
+ // 获取登录用户地址
|
|
|
+ String interface_url = wechatConfig.getPortUrl() + "prod-api/system/oauth2/user/get";
|
|
|
+
|
|
|
+ HttpRequest httpRequest = HttpUtil.createGet(interface_url);
|
|
|
+ httpRequest.header("Authorization", "Bearer " + token);
|
|
|
+ httpRequest.header("Token", token);
|
|
|
+ JSONObject resultJson = JSONUtil.parseObj(httpRequest.execute().body());
|
|
|
+
|
|
|
+ log.info("单点登录返回内容:{},业务域名:{}", resultJson, interface_url);
|
|
|
+
|
|
|
+ openId = resultJson.getJSONObject("data").getStr("wxxcxOpenid");
|
|
|
+ ssoId = resultJson.getJSONObject("data").getStr("wxUnionid");
|
|
|
+ Map<String, String> map = new HashMap<>(2);
|
|
|
+ map.put("ssoId", ssoId);
|
|
|
+ map.put("openId", openId);
|
|
|
+ if (StrUtil.isEmpty(ssoId) || StrUtil.isEmpty(openId)) {
|
|
|
+ throw new ServiceException(String.format("获取用户失败,token:%s,业务域名:%s", token, interface_url));
|
|
|
+ }
|
|
|
+ return map;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
}
|