123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389 |
- package org.jeecg.modules.system.controller;
- import com.alibaba.fastjson.JSONObject;
- import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
- import com.xkcoding.justauth.AuthRequestFactory;
- import io.swagger.annotations.ApiOperation;
- import lombok.extern.slf4j.Slf4j;
- import me.zhyd.oauth.model.AuthCallback;
- import me.zhyd.oauth.model.AuthResponse;
- import me.zhyd.oauth.request.AuthRequest;
- import me.zhyd.oauth.utils.AuthStateUtils;
- import org.jeecg.common.api.vo.Result;
- import org.jeecg.common.constant.CommonConstant;
- import org.jeecg.common.system.util.JwtUtil;
- import org.jeecg.common.util.PasswordUtil;
- import org.jeecg.common.util.RedisUtil;
- import org.jeecg.common.util.RestUtil;
- import org.jeecg.common.util.oConvertUtils;
- import org.jeecg.config.thirdapp.ThirdAppConfig;
- import org.jeecg.config.thirdapp.ThirdAppTypeItemVo;
- import org.jeecg.modules.base.service.BaseCommonService;
- import org.jeecg.modules.system.entity.SysThirdAccount;
- import org.jeecg.modules.system.entity.SysUser;
- import org.jeecg.modules.system.model.ThirdLoginModel;
- import org.jeecg.modules.system.service.ISysThirdAccountService;
- import org.jeecg.modules.system.service.ISysUserService;
- import org.jeecg.modules.system.service.impl.ThirdAppDingtalkServiceImpl;
- import org.jeecg.modules.system.service.impl.ThirdAppWechatEnterpriseServiceImpl;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Controller;
- import org.springframework.ui.ModelMap;
- import org.springframework.web.bind.annotation.*;
- import javax.servlet.http.HttpServletResponse;
- import java.io.IOException;
- import java.io.UnsupportedEncodingException;
- import java.net.URLEncoder;
- import java.util.List;
- /**
- * @Author scott
- * @since 2018-12-17
- */
- @Controller
- @RequestMapping("/sys/thirdLogin")
- @Slf4j
- public class ThirdLoginController {
- @Autowired
- private ISysUserService sysUserService;
- @Autowired
- private ISysThirdAccountService sysThirdAccountService;
- @Autowired
- private BaseCommonService baseCommonService;
- @Autowired
- private RedisUtil redisUtil;
- @Autowired
- private AuthRequestFactory factory;
- @Autowired
- ThirdAppConfig thirdAppConfig;
- @Autowired
- private ThirdAppWechatEnterpriseServiceImpl thirdAppWechatEnterpriseService;
- @Autowired
- private ThirdAppDingtalkServiceImpl thirdAppDingtalkService;
- @RequestMapping("/render/{source}")
- public void render(@PathVariable("source") String source, HttpServletResponse response) throws IOException {
- log.info("第三方登录进入render:" + source);
- AuthRequest authRequest = factory.get(source);
- String authorizeUrl = authRequest.authorize(AuthStateUtils.createState());
- log.info("第三方登录认证地址:" + authorizeUrl);
- response.sendRedirect(authorizeUrl);
- }
- @RequestMapping("/{source}/callback")
- public String loginThird(@PathVariable("source") String source, AuthCallback callback,ModelMap modelMap) {
- log.info("第三方登录进入callback:" + source + " params:" + JSONObject.toJSONString(callback));
- AuthRequest authRequest = factory.get(source);
- AuthResponse response = authRequest.login(callback);
- log.info(JSONObject.toJSONString(response));
- Result<JSONObject> result = new Result<JSONObject>();
- if(response.getCode()==2000) {
- JSONObject data = JSONObject.parseObject(JSONObject.toJSONString(response.getData()));
- String username = data.getString("username");
- String avatar = data.getString("avatar");
- String uuid = data.getString("uuid");
- //构造第三方登录信息存储对象
- ThirdLoginModel tlm = new ThirdLoginModel(source, uuid, username, avatar);
- //判断有没有这个人
- //update-begin-author:wangshuai date:20201118 for:修改成查询第三方账户表
- LambdaQueryWrapper<SysThirdAccount> query = new LambdaQueryWrapper<SysThirdAccount>();
- query.eq(SysThirdAccount::getThirdUserUuid, uuid);
- query.eq(SysThirdAccount::getThirdType, source);
- List<SysThirdAccount> thridList = sysThirdAccountService.list(query);
- SysThirdAccount user = null;
- if(thridList==null || thridList.size()==0) {
- //否则直接创建新账号
- user = sysThirdAccountService.saveThirdUser(tlm);
- }else {
- //已存在 只设置用户名 不设置头像
- user = thridList.get(0);
- }
- // 生成token
- //update-begin-author:wangshuai date:20201118 for:从第三方登录查询是否存在用户id,不存在绑定手机号
- if(oConvertUtils.isNotEmpty(user.getSysUserId())) {
- String sysUserId = user.getSysUserId();
- SysUser sysUser = sysUserService.getById(sysUserId);
- String token = saveToken(sysUser);
- modelMap.addAttribute("token", token);
- }else{
- modelMap.addAttribute("token", "绑定手机号,"+""+uuid);
- }
- //update-end-author:wangshuai date:20201118 for:从第三方登录查询是否存在用户id,不存在绑定手机号
- //update-begin--Author:wangshuai Date:20200729 for:接口在签名校验失败时返回失败的标识码 issues#1441--------------------
- }else{
- modelMap.addAttribute("token", "登录失败");
- }
- //update-end--Author:wangshuai Date:20200729 for:接口在签名校验失败时返回失败的标识码 issues#1441--------------------
- result.setSuccess(false);
- result.setMessage("第三方登录异常,请联系管理员");
- return "thirdLogin";
- }
- /**
- * 创建新账号
- * @param model
- * @return
- */
- @PostMapping("/user/create")
- @ResponseBody
- public Result<String> thirdUserCreate(@RequestBody ThirdLoginModel model) {
- log.info("第三方登录创建新账号:" );
- Result<String> res = new Result<>();
- Object operateCode = redisUtil.get(CommonConstant.THIRD_LOGIN_CODE);
- if(operateCode==null || !operateCode.toString().equals(model.getOperateCode())){
- res.setSuccess(false);
- res.setMessage("校验失败");
- return res;
- }
- //创建新账号
- //update-begin-author:wangshuai date:20201118 for:修改成从第三方登录查出来的user_id,在查询用户表尽行token
- SysThirdAccount user = sysThirdAccountService.saveThirdUser(model);
- if(oConvertUtils.isNotEmpty(user.getSysUserId())){
- String sysUserId = user.getSysUserId();
- SysUser sysUser = sysUserService.getById(sysUserId);
- // 生成token
- String token = saveToken(sysUser);
- //update-end-author:wangshuai date:20201118 for:修改成从第三方登录查出来的user_id,在查询用户表尽行token
- res.setResult(token);
- res.setSuccess(true);
- }
- return res;
- }
- /**
- * 绑定账号 需要设置密码 需要走一遍校验
- * @param json
- * @return
- */
- @PostMapping("/user/checkPassword")
- @ResponseBody
- public Result<String> checkPassword(@RequestBody JSONObject json) {
- Result<String> result = new Result<>();
- Object operateCode = redisUtil.get(CommonConstant.THIRD_LOGIN_CODE);
- if(operateCode==null || !operateCode.toString().equals(json.getString("operateCode"))){
- result.setSuccess(false);
- result.setMessage("校验失败");
- return result;
- }
- String username = json.getString("uuid");
- SysUser user = this.sysUserService.getUserByName(username);
- if(user==null){
- result.setMessage("用户未找到");
- result.setSuccess(false);
- return result;
- }
- String password = json.getString("password");
- String salt = user.getSalt();
- String passwordEncode = PasswordUtil.encrypt(user.getUsername(), password, salt);
- if(!passwordEncode.equals(user.getPassword())){
- result.setMessage("密码不正确");
- result.setSuccess(false);
- return result;
- }
- sysUserService.updateById(user);
- result.setSuccess(true);
- // 生成token
- String token = saveToken(user);
- result.setResult(token);
- return result;
- }
- private String saveToken(SysUser user) {
- // 生成token
- String token = JwtUtil.sign(user.getUsername(), user.getPassword());
- redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
- // 设置超时时间
- redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME / 1000);
- return token;
- }
- @SuppressWarnings("unchecked")
- @RequestMapping(value = "/getLoginUser/{token}/{thirdType}", method = RequestMethod.GET)
- @ResponseBody
- public Result<JSONObject> getThirdLoginUser(@PathVariable("token") String token,@PathVariable("thirdType") String thirdType) throws Exception {
- Result<JSONObject> result = new Result<JSONObject>();
- String username = JwtUtil.getUsername(token);
- //1. 校验用户是否有效
- SysUser sysUser = sysUserService.getUserByName(username);
- result = sysUserService.checkUserIsEffective(sysUser);
- if(!result.isSuccess()) {
- return result;
- }
- //update-begin-author:wangshuai date:20201118 for:如果真实姓名和头像不存在就取第三方登录的
- LambdaQueryWrapper<SysThirdAccount> query = new LambdaQueryWrapper<>();
- query.eq(SysThirdAccount::getSysUserId,sysUser.getId());
- query.eq(SysThirdAccount::getThirdType,thirdType);
- SysThirdAccount account = sysThirdAccountService.getOne(query);
- if(oConvertUtils.isEmpty(sysUser.getRealname())){
- sysUser.setRealname(account.getRealname());
- }
- if(oConvertUtils.isEmpty(sysUser.getAvatar())){
- sysUser.setAvatar(account.getAvatar());
- }
- //update-end-author:wangshuai date:20201118 for:如果真实姓名和头像不存在就取第三方登录的
- JSONObject obj = new JSONObject();
- //用户登录信息
- obj.put("userInfo", sysUser);
- //token 信息
- obj.put("token", token);
- result.setResult(obj);
- result.setSuccess(true);
- result.setCode(200);
- baseCommonService.addLog("用户名: " + username + ",登录成功[第三方用户]!", CommonConstant.LOG_TYPE_1, null);
- return result;
- }
- /**
- * 第三方绑定手机号返回token
- *
- * @param jsonObject
- * @return
- */
- @ApiOperation("手机号登录接口")
- @PostMapping("/bindingThirdPhone")
- @ResponseBody
- public Result<String> bindingThirdPhone(@RequestBody JSONObject jsonObject) {
- Result<String> result = new Result<String>();
- String phone = jsonObject.getString("mobile");
- String thirdUserUuid = jsonObject.getString("thirdUserUuid");
- //校验用户有效性
- SysUser sysUser = sysUserService.getUserByPhone(phone);
- if(sysUser != null){
- sysThirdAccountService.updateThirdUserId(sysUser,thirdUserUuid);
- }else{
- // 不存在手机号,创建用户
- String smscode = jsonObject.getString("captcha");
- Object code = redisUtil.get(phone);
- if (!smscode.equals(code)) {
- result.setMessage("手机验证码错误");
- result.setSuccess(false);
- return result;
- }
- //创建用户
- sysUser = sysThirdAccountService.createUser(phone,thirdUserUuid);
- }
- String token = saveToken(sysUser);
- result.setSuccess(true);
- result.setResult(token);
- return result;
- }
- /**
- * 企业微信/钉钉 OAuth2登录
- *
- * @param source
- * @param state
- * @return
- */
- @ResponseBody
- @GetMapping("/oauth2/{source}/login")
- public String oauth2LoginCallback(@PathVariable("source") String source, @RequestParam("state") String state, HttpServletResponse response) throws Exception {
- String url;
- if (ThirdAppConfig.WECHAT_ENTERPRISE.equalsIgnoreCase(source)) {
- ThirdAppTypeItemVo config = thirdAppConfig.getWechatEnterprise();
- StringBuilder builder = new StringBuilder();
- // 构造企业微信OAuth2登录授权地址
- builder.append("https://open.weixin.qq.com/connect/oauth2/authorize");
- // 企业的CorpID
- builder.append("?appid=").append(config.getClientId());
- // 授权后重定向的回调链接地址,请使用urlencode对链接进行处理
- String redirectUri = RestUtil.getBaseUrl() + "/sys/thirdLogin/oauth2/wechat_enterprise/callback";
- builder.append("&redirect_uri=").append(URLEncoder.encode(redirectUri, "UTF-8"));
- // 返回类型,此时固定为:code
- builder.append("&response_type=code");
- // 应用授权作用域。
- // snsapi_base:静默授权,可获取成员的的基础信息(UserId与DeviceId);
- builder.append("&scope=snsapi_base");
- // 重定向后会带上state参数,长度不可超过128个字节
- builder.append("&state=").append(state);
- // 终端使用此参数判断是否需要带上身份信息
- builder.append("#wechat_redirect");
- url = builder.toString();
- } else if (ThirdAppConfig.DINGTALK.equalsIgnoreCase(source)) {
- ThirdAppTypeItemVo config = thirdAppConfig.getDingtalk();
- StringBuilder builder = new StringBuilder();
- // 构造钉钉OAuth2登录授权地址
- builder.append("https://login.dingtalk.com/oauth2/auth");
- // 授权通过/拒绝后回调地址。
- // 注意 需要与注册应用时登记的域名保持一致。
- String redirectUri = RestUtil.getBaseUrl() + "/sys/thirdLogin/oauth2/dingtalk/callback";
- builder.append("?redirect_uri=").append(URLEncoder.encode(redirectUri, "UTF-8"));
- // 固定值为code。
- // 授权通过后返回authCode。
- builder.append("&response_type=code");
- // 步骤一中创建的应用详情中获取。
- // 企业内部应用:client_id为应用的AppKey。
- builder.append("&client_id=").append(config.getClientId());
- // 授权范围,授权页面显示的授权信息以应用注册时配置的为准。
- // openid:授权后可获得用户userid
- builder.append("&scope=openid");
- // 跟随authCode原样返回。
- builder.append("&state=").append(state);
- url = builder.toString();
- } else {
- return "不支持的source";
- }
- log.info("oauth2 login url:" + url);
- response.sendRedirect(url);
- return "login…";
- }
- /**
- * 企业微信/钉钉 OAuth2登录回调
- *
- * @param code
- * @param state
- * @param response
- * @return
- */
- @ResponseBody
- @GetMapping("/oauth2/{source}/callback")
- public String oauth2LoginCallback(
- @PathVariable("source") String source,
- // 企业微信返回的code
- @RequestParam(value = "code", required = false) String code,
- // 钉钉返回的code
- @RequestParam(value = "authCode", required = false) String authCode,
- @RequestParam("state") String state,
- HttpServletResponse response
- ) {
- SysUser loginUser;
- if (ThirdAppConfig.WECHAT_ENTERPRISE.equalsIgnoreCase(source)) {
- log.info("【企业微信】OAuth2登录进入callback:code=" + code + ", state=" + state);
- loginUser = thirdAppWechatEnterpriseService.oauth2Login(code);
- if (loginUser == null) {
- return "登录失败";
- }
- } else if (ThirdAppConfig.DINGTALK.equalsIgnoreCase(source)) {
- log.info("【钉钉】OAuth2登录进入callback:authCode=" + authCode + ", state=" + state);
- loginUser = thirdAppDingtalkService.oauth2Login(authCode);
- if (loginUser == null) {
- return "登录失败";
- }
- } else {
- return "不支持的source";
- }
- try {
- String token = saveToken(loginUser);
- state += "/oauth2-app/login?oauth2LoginToken=" + URLEncoder.encode(token, "UTF-8");
- state += "&thirdType=" + "wechat_enterprise";
- log.info("OAuth2登录重定向地址: " + state);
- try {
- response.sendRedirect(state);
- return "ok";
- } catch (IOException e) {
- e.printStackTrace();
- return "重定向失败";
- }
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- return "解码失败";
- }
- }
- }
|