SocialsTokenGranter.java 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. package jnpf.granter;
  2. import cn.dev33.satoken.context.SaHolder;
  3. import cn.dev33.satoken.context.model.SaRequest;
  4. import cn.dev33.satoken.stp.StpUtil;
  5. import cn.dev33.satoken.util.SaFoxUtil;
  6. import cn.hutool.core.collection.CollectionUtil;
  7. import com.alibaba.fastjson.JSONArray;
  8. import com.alibaba.fastjson.JSONObject;
  9. import jnpf.base.ActionResult;
  10. import jnpf.base.UserInfo;
  11. import jnpf.constant.MsgCode;
  12. import jnpf.consts.AuthConsts;
  13. import jnpf.consts.LoginTicketStatus;
  14. import jnpf.exception.LoginException;
  15. import jnpf.model.BaseSystemInfo;
  16. import jnpf.model.LoginTicketModel;
  17. import jnpf.model.SocialUnbindModel;
  18. import jnpf.model.LoginVO;
  19. import jnpf.permission.controller.SocialsUserController;
  20. import jnpf.permission.model.socails.SocialsUserInfo;
  21. import jnpf.util.ServletUtil;
  22. import jnpf.util.StringUtil;
  23. import jnpf.util.TicketUtil;
  24. import jnpf.util.UserProvider;
  25. import lombok.extern.slf4j.Slf4j;
  26. import org.springframework.beans.factory.annotation.Autowired;
  27. import org.springframework.stereotype.Component;
  28. import jakarta.servlet.http.HttpServletResponse;
  29. import java.io.PrintWriter;
  30. import java.util.Map;
  31. import java.util.Objects;
  32. import static jnpf.granter.SocialsTokenGranter.GRANT_TYPE;
  33. @Slf4j
  34. @Component(GRANT_TYPE)
  35. public class SocialsTokenGranter extends AbstractTokenGranter {
  36. public static final String GRANT_TYPE = "socials";
  37. public static final Integer ORDER = 5;
  38. private static final String URL_LOGIN = "/Login/socials/**";
  39. @Autowired
  40. private SocialsUserController socialsUserApi;
  41. public SocialsTokenGranter() {
  42. super(URL_LOGIN);
  43. }
  44. protected String getGrantType() {
  45. return GRANT_TYPE;
  46. }
  47. public ActionResult granter(Map<String, String> map) throws LoginException {
  48. SaRequest req = SaHolder.getRequest();
  49. String code = req.getParam("code");
  50. String state = req.getParam("state");
  51. String source = req.getParam("source");
  52. String uuid = req.getParam("uuid");
  53. if (StringUtil.isEmpty(code)) {
  54. code = req.getParam("authCode") != null ? req.getParam("authCode") : req.getParam("auth_code");
  55. }
  56. //是否是微信qq唤醒或者小程序登录
  57. if (StringUtil.isNotEmpty(uuid)) {
  58. try {
  59. return loginByCode(source, code, null, uuid, null);
  60. } catch (Exception e) {
  61. //更新登录结果
  62. outError(e.getMessage());
  63. }
  64. }
  65. //租户列表登陆标识
  66. boolean tenantLogin = "true".equalsIgnoreCase(req.getParam("tenantLogin"));
  67. if (tenantLogin) {
  68. //租户多绑定选择登录
  69. if(configValueUtil.isMultiTenancy()) {
  70. LoginVO loginVO = tenantLogin(req);
  71. return ActionResult.success(MsgCode.OA015.get(), loginVO);
  72. }
  73. } else if (StringUtil.isEmpty(req.getParam(AuthConsts.PARAMS_JNPF_TICKET))) {
  74. //个人中心绑定
  75. if (SaFoxUtil.isNotEmpty(code)) {
  76. socialsBinding(req, code, state, source);
  77. }
  78. } else{
  79. //票据登陆
  80. if (!isValidJnpfTicket()) {
  81. outError(MsgCode.OA016.get());
  82. return null;
  83. }
  84. //接受CODE 进行登录
  85. if (SaFoxUtil.isNotEmpty(code)) {
  86. try {
  87. String socialName = req.getParam("socialName");
  88. ActionResult actionResult = loginByCode(source, code, state, null, socialName);
  89. if (400 == actionResult.getCode() || "wechat_applets".equals(req.getParam("source"))) {
  90. return actionResult;
  91. }
  92. return null;
  93. } catch (Exception e) {
  94. //更新登录结果
  95. outError(e.getMessage());
  96. }
  97. return null;
  98. }
  99. }
  100. return null;
  101. }
  102. /**
  103. * 租户列表登录
  104. *
  105. * @param
  106. * @return
  107. * @copyright 引迈信息技术有限公司
  108. * @date 2022/9/21
  109. */
  110. private LoginVO tenantLogin(SaRequest req) throws LoginException {
  111. String ticket = getJnpfTicket();
  112. if (StringUtil.isEmpty(ticket)) {
  113. throw new LoginException(MsgCode.OA016.get());
  114. }
  115. LoginTicketModel loginTicketModel = TicketUtil.parseTicket(ticket);
  116. if (loginTicketModel == null) {
  117. throw new LoginException(MsgCode.OA016.get());
  118. }
  119. TicketUtil.deleteTicket(ticket);
  120. JSONArray tenantArr = JSONArray.parseArray(loginTicketModel.getValue());
  121. String id = req.getParam("id");
  122. JSONObject tenantInfo = null;
  123. for (int i = 0; i < tenantArr.size(); i++) {
  124. JSONObject o = tenantArr.getJSONObject(i);
  125. if (Objects.equals(id, o.getString("id"))) {
  126. tenantInfo = o;
  127. break;
  128. }
  129. }
  130. if (tenantInfo != null) {
  131. String userId = tenantInfo.getString("userId");
  132. String account = tenantInfo.getString("account");
  133. String tenantId = tenantInfo.getString("tenantId");
  134. UserInfo userInfo = UserProvider.getLocalLoginUser();
  135. userInfo.setUserId(userId);
  136. userInfo.setTenantId(tenantId);
  137. userInfo.setUserAccount(tenantId + "@" + account);
  138. //切换租户
  139. switchTenant(userInfo);
  140. //获取系统配置
  141. BaseSystemInfo baseSystemInfo = getSysconfig(userInfo);
  142. //登录账号
  143. super.loginAccount(userInfo, baseSystemInfo);
  144. //返回登录信息
  145. LoginVO loginVo = getLoginVo(userInfo);
  146. return loginVo;
  147. }
  148. throw new LoginException(MsgCode.OA016.get());
  149. }
  150. /**
  151. * 第三方绑定
  152. */
  153. private void socialsBinding(SaRequest req, String code, String state, String source) {
  154. String userId = req.getParam("userId");
  155. String tenantId = req.getParam("tenantId");
  156. try {
  157. HttpServletResponse response = ServletUtil.getResponse();
  158. response.setCharacterEncoding("utf-8");
  159. response.setHeader("content-type", "text/html;charset=utf-8");
  160. PrintWriter out = response.getWriter();
  161. JSONObject binding = socialsUserApi.binding(source, userId, tenantId, code, state);
  162. out.print(
  163. "<script>\n" +
  164. "window.opener.postMessage(\'" + binding.toJSONString() + "\', '*');\n" +
  165. "window.open('','_self','');\n" +
  166. "window.close();\n" + "</script>");
  167. } catch (Exception e) {
  168. }
  169. }
  170. public ActionResult logout() {
  171. return super.logout();
  172. }
  173. public int getOrder() {
  174. return ORDER;
  175. }
  176. protected void outError(String message) {
  177. updateTicketError(message);
  178. }
  179. @Override
  180. protected String getUserDetailKey() {
  181. return AuthConsts.USERDETAIL_USER_ID;
  182. }
  183. protected LoginTicketModel getTicketUnbind(String socialType, String socialUnionid, String socialName) {
  184. LoginTicketModel loginTicketModel = null;
  185. SocialUnbindModel obj = new SocialUnbindModel(socialType, socialUnionid, socialName);
  186. String ticket = this.getJnpfTicket();
  187. if (!ticket.isEmpty()) {
  188. loginTicketModel = (new LoginTicketModel()).setStatus(LoginTicketStatus.UnBind.getStatus()).setValue(JSONObject.toJSONString(obj));
  189. }
  190. return loginTicketModel;
  191. }
  192. protected LoginTicketModel getTicketMultitenancy(JSONArray jsonArray) {
  193. LoginTicketModel loginTicketModel = null;
  194. String ticket = this.getJnpfTicket();
  195. if (!ticket.isEmpty()) {
  196. loginTicketModel = (new LoginTicketModel()).setStatus(LoginTicketStatus.Multitenancy.getStatus()).setValue(jsonArray.toJSONString());
  197. }
  198. return loginTicketModel;
  199. }
  200. protected LoginTicketModel getTicketSuccessReturn(UserInfo userInfo) {
  201. LoginTicketModel loginTicketModel = null;
  202. String ticket = getJnpfTicket();
  203. if (!ticket.isEmpty()) {
  204. loginTicketModel = new LoginTicketModel()
  205. .setStatus(LoginTicketStatus.Success.getStatus())
  206. .setValue(StpUtil.getTokenValueNotCut())
  207. .setTheme(userInfo.getTheme());
  208. TicketUtil.updateTicket(ticket, loginTicketModel, null);
  209. }
  210. return loginTicketModel;
  211. }
  212. protected LoginTicketModel updateTicket(LoginTicketModel loginTicketModel) {
  213. String ticket = getJnpfTicket();
  214. if (!ticket.isEmpty()) {
  215. boolean needClose = false;
  216. String userAgent = ServletUtil.getUserAgent();
  217. if (userAgent.contains("wxwork")) {
  218. needClose = true;
  219. }
  220. if(needClose) {
  221. // 浏览器中扫码, 选择客户端打开, 需要把客户端打开的页面关闭
  222. try {
  223. HttpServletResponse response = ServletUtil.getResponse();
  224. PrintWriter out = response.getWriter();
  225. response.setCharacterEncoding("utf-8");
  226. response.setHeader("content-type", "text/html;charset=utf-8");
  227. out.print(
  228. "<script>\n" +
  229. "window.close();\n" + "</script>");
  230. } catch (Exception e) {
  231. }
  232. }
  233. TicketUtil.updateTicket(ticket, loginTicketModel, null);
  234. }
  235. return loginTicketModel;
  236. }
  237. protected LoginVO getLoginVo(UserInfo userInfo) {
  238. LoginVO loginVO = new LoginVO();
  239. loginVO.setTheme(userInfo.getTheme());
  240. loginVO.setToken(userInfo.getToken());
  241. return loginVO;
  242. }
  243. /**
  244. * 小程序登录微信授权
  245. * app微信,qq唤醒
  246. *
  247. * @param code
  248. * @throws LoginException
  249. */
  250. protected ActionResult loginByCode(String source, String code, String state, String uuid, String socialName) throws LoginException {
  251. log.debug("Auth2 Code: {}", code);
  252. SocialsUserInfo socialsUserInfo = null;
  253. if (StringUtil.isNotEmpty(code)) {
  254. socialsUserInfo = socialsUserApi.getSocialsUserInfo(source, code, state);
  255. } else if (StringUtil.isNotEmpty(uuid)) {//微信和qq唤醒
  256. socialsUserInfo = socialsUserApi.getUserInfo(source, uuid, state);
  257. if (StringUtil.isEmpty(socialsUserInfo.getSocialName()) && StringUtil.isNotEmpty(socialName)) {
  258. socialsUserInfo.setSocialName(socialName);//小程序名称前端传递
  259. }
  260. }
  261. if (configValueUtil.isMultiTenancy()) {
  262. if (socialsUserInfo == null || CollectionUtil.isEmpty(socialsUserInfo.getTenantUserInfo())) {
  263. //第三方未绑定账号!
  264. LoginTicketModel ticketModel = getTicketUnbind(source, socialsUserInfo.getSocialUnionid(), socialsUserInfo.getSocialName());
  265. updateTicket(ticketModel);
  266. return ActionResult.fail(MsgCode.OA017.get());
  267. }
  268. if (socialsUserInfo.getTenantUserInfo().size() == 1) {
  269. UserInfo userInfo = socialsUserInfo.getUserInfo();
  270. //切换租户
  271. switchTenant(userInfo);
  272. //获取系统配置
  273. BaseSystemInfo baseSystemInfo = getSysconfig(userInfo);
  274. //登录账号
  275. super.loginAccount(userInfo, baseSystemInfo);
  276. //返回登录信息
  277. LoginTicketModel loginTicketModel = getTicketSuccessReturn(userInfo);
  278. updateTicket(loginTicketModel);
  279. return ActionResult.success();
  280. } else {
  281. JSONArray tenantUserInfo = socialsUserInfo.getTenantUserInfo();
  282. for (int i = 0; i < tenantUserInfo.size(); i++) {
  283. JSONObject o = tenantUserInfo.getJSONObject(i);
  284. o.remove("socialId");
  285. o.remove("socialType");
  286. }
  287. LoginTicketModel loginTicketModel = getTicketMultitenancy(tenantUserInfo);
  288. updateTicket(loginTicketModel);
  289. return ActionResult.success(loginTicketModel);
  290. }
  291. } else {
  292. if (socialsUserInfo == null || socialsUserInfo.getUserInfo() == null) {
  293. LoginTicketModel ticketModel = getTicketUnbind(source, socialsUserInfo.getSocialUnionid(), socialsUserInfo.getSocialName());//第三方未绑定账号!
  294. updateTicket(ticketModel);
  295. return ActionResult.fail(MsgCode.OA017.get());
  296. }
  297. UserInfo userInfo = socialsUserInfo.getUserInfo();
  298. //切换租户
  299. switchTenant(userInfo);
  300. //获取系统配置
  301. BaseSystemInfo baseSystemInfo = getSysconfig(userInfo);
  302. //登录账号
  303. super.loginAccount(userInfo, baseSystemInfo);
  304. LoginTicketModel loginTicketModel = getTicketSuccessReturn(userInfo);
  305. updateTicket(loginTicketModel);
  306. return ActionResult.success();
  307. }
  308. }
  309. }