Przeglądaj źródła

微信端单点登录

xiari 1 rok temu
rodzic
commit
c6033169c6

+ 16 - 0
ruoyi-auth/src/main/java/org/dromara/auth/config/WechatConfig.java

@@ -0,0 +1,16 @@
+package org.dromara.auth.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+@Data
+@Configuration
+@ConfigurationProperties("wechat.config")
+public class WechatConfig {
+    private String domainName;
+    private String contextPath;
+    private String portUrl;
+    private String clientId;
+    private String clientSecret;
+}

+ 34 - 0
ruoyi-auth/src/main/java/org/dromara/auth/controller/TokenController.java

@@ -22,6 +22,7 @@ import org.dromara.auth.service.SysLoginService;
 import org.dromara.common.core.constant.UserConstants;
 import org.dromara.common.core.domain.R;
 import org.dromara.common.core.domain.model.LoginBody;
+import org.dromara.common.core.exception.ServiceException;
 import org.dromara.common.core.utils.*;
 import org.dromara.common.encrypt.annotation.ApiEncrypt;
 import org.dromara.common.json.utils.JsonUtils;
@@ -44,6 +45,7 @@ import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
 
@@ -107,6 +109,31 @@ public class TokenController {
         return R.ok(loginVo);
     }
 
+    /**
+     * 小程序登录
+     *
+     * @param body 登录信息
+     * @return 结果
+     */
+    @PostMapping("/codeLogin")
+    public R<LoginVo> xcxLogin(@RequestBody String body) {
+        // 小程序登录
+        String s = Base64.decodeStr(body);
+        LoginBody loginBody = JsonUtils.parseObject(s, LoginBody.class);
+        LoginBody loginInfo = Optional.ofNullable(loginBody).orElse(new LoginBody());
+        String code = loginInfo.getCode();
+        String grantType = loginInfo.getGrantType();
+        String otherInfo = loginInfo.getOtherInfo();
+        if(StringUtils.isBlank(code) || !"android".equals(grantType) || StringUtils.isBlank(otherInfo)){
+            throw new ServiceException("参数缺失或有误!");
+        }
+        LoginVo loginVo = sysLoginService.codeLogin(code, otherInfo);
+        Long userId = LoginHelper.getUserId();
+
+        return R.ok(loginVo);
+    }
+
+
     /**
      * 第三方登录请求
      *
@@ -228,4 +255,11 @@ public class TokenController {
         return R.ok(result);
     }
 
+    public static void main(String[] args) {
+        String str = "W3sidmFsdWUiOiIxMCIsInRleHQiOiIxMOWFgyIsImlzQ2hvb3NlIjpmYWxzZX0seyJ2YWx1ZSI6IjIwIiwidGV4dCI6IjIw5YWDIiwiaXNDaG9vc2UiOmZhbHNlfSx7InZhbHVlIjoiNTAiLCJ0ZXh0IjoiNTDlhYMiLCJpc0Nob29zZSI6ZmFsc2V9LHsidmFsdWUiOiIxMDAiLCJ0ZXh0IjoiMTAw5YWDIiwiaXNDaG9vc2UiOmZhbHNlfSx7InZhbHVlIjoiMjAwIiwidGV4dCI6IjIwMOWFgyIsImlzQ2hvb3NlIjpmYWxzZX0seyJ2YWx1ZSI6IjUwMCIsInRleHQiOiI1MDDlhYMiLCJpc0Nob29zZSI6ZmFsc2V9XQ==";
+        String s = Base64.decodeStr(str);
+        System.err.println(s);
+
+    }
+
 }

+ 2 - 0
ruoyi-auth/src/main/java/org/dromara/auth/domain/vo/LoginVo.java

@@ -51,4 +51,6 @@ public class LoginVo {
      */
     private String openid;
 
+    private String otherSysId;
+
 }

+ 148 - 0
ruoyi-auth/src/main/java/org/dromara/auth/service/SysLoginService.java

@@ -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;
+    }
+
+
 }

+ 2 - 0
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginBody.java

@@ -40,4 +40,6 @@ public class LoginBody {
      */
     private String uuid;
 
+    private String otherInfo;
+
 }

+ 10 - 8
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/wx/contorller/WxController.java

@@ -9,6 +9,7 @@ import org.dromara.common.core.api.ResponseResult;
 import org.dromara.common.core.domain.R;
 import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.satoken.utils.LoginHelper;
 import org.dromara.common.web.core.BaseController;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
@@ -32,9 +33,9 @@ public class WxController extends BaseController {
      * @param userId
      * @return
      */
-    @GetMapping("/getUserInfo/{userId}")
-    public R<PtUserAccountVo> getUserInfo(@NotNull(message = "用户ID不能为空")
-                               @PathVariable Long userId) {
+    @GetMapping("/getUserInfo")
+    public R<PtUserAccountVo> getUserInfo() {
+        Long userId = LoginHelper.getUserId();
         return R.ok(wxService.getUserInfoByUserId(userId));
     }
 
@@ -43,15 +44,16 @@ public class WxController extends BaseController {
      * @param userId
      * @return
      */
-    @GetMapping("/findCreditAccount/{userId}")
-    public TableDataInfo<WxCreditAccountVo> findCreditAccount(@NotNull(message = "用户ID不能为空")
-                                          @PathVariable Long userId, String startTime, String endTime,
+    @GetMapping("/findCreditAccount")
+    public TableDataInfo<WxCreditAccountVo> findCreditAccount(String startTime, String endTime,
                                                               PageQuery pageQuery) {
+        Long userId = LoginHelper.getUserId();
         return wxService.findCreditAccount(userId, startTime, endTime, pageQuery);
     }
 
-    @PutMapping("/updateCardStatus/{userId}")
-    public R<Void> lockPtCard(@PathVariable Long userId, String cardStatus) {
+    @PutMapping("/updateCardStatus")
+    public R<Void> lockPtCard(String cardStatus) {
+        Long userId = LoginHelper.getUserId();
         return toAjax(wxService.updateCardStatus(userId, cardStatus));
     }
 }