From 58dff6ffed5cd370fd7ed3ec0ae1c1b8ebd0f062 Mon Sep 17 00:00:00 2001 From: liyawei Date: Fri, 18 Mar 2022 18:31:18 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8D=95=E7=82=B9=E7=99=BB=E5=BD=95-=E5=BE=85?= =?UTF-8?q?=E8=B0=83=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/jero/config/shiro/ShiroConfig.java | 2 + .../modules/opensso/URLRequestResultUtil.java | 56 +++++ .../controller/SSOLoginController.java | 205 ++++++++++++++++++ .../src/main/resources/application-dev.yml | 2 + 4 files changed, 265 insertions(+) create mode 100644 jero-boot/jero-boot-module-system/src/main/java/com/jero/modules/opensso/URLRequestResultUtil.java create mode 100644 jero-boot/jero-boot-module-system/src/main/java/com/jero/modules/opensso/controller/SSOLoginController.java diff --git a/jero-boot/jero-boot-base/jero-boot-base-core/src/main/java/com/jero/config/shiro/ShiroConfig.java b/jero-boot/jero-boot-base/jero-boot-base-core/src/main/java/com/jero/config/shiro/ShiroConfig.java index 285b1a5fa..7be076571 100644 --- a/jero-boot/jero-boot-base/jero-boot-base-core/src/main/java/com/jero/config/shiro/ShiroConfig.java +++ b/jero-boot/jero-boot-base/jero-boot-base-core/src/main/java/com/jero/config/shiro/ShiroConfig.java @@ -134,6 +134,8 @@ public class ShiroConfig { //性能监控 TODO 存在安全漏洞泄露TOEKN(durid连接池也有) filterChainDefinitionMap.put("/actuator/**", "anon"); + filterChainDefinitionMap.put("/opensso/**", "anon"); //单点登录 + // 添加自己的过滤器并且取名为jwt Map filterMap = new HashMap(1); //如果cloudServer为空 则说明是单体 需要加载跨域配置 diff --git a/jero-boot/jero-boot-module-system/src/main/java/com/jero/modules/opensso/URLRequestResultUtil.java b/jero-boot/jero-boot-module-system/src/main/java/com/jero/modules/opensso/URLRequestResultUtil.java new file mode 100644 index 000000000..30935001a --- /dev/null +++ b/jero-boot/jero-boot-module-system/src/main/java/com/jero/modules/opensso/URLRequestResultUtil.java @@ -0,0 +1,56 @@ +package com.jero.modules.opensso; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; + +/** + * @Description + * @Author liyawei + * @Create 2021/8/17 + */ +public class URLRequestResultUtil { + public static String getProxyRequestResult(String url) { + StringBuffer requestResult = new StringBuffer(); + BufferedReader in = null; + + try { + System.out.println(url); + URL realUrl = new URL(url); + // 打开和URL之间的连接 + URLConnection connection = realUrl.openConnection(); + // 设置通用的请求属性 + connection.setRequestProperty("accept", "*/*"); + connection.setRequestProperty("connection", "Keep-Alive"); + connection.setRequestProperty("user-agent", + "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); + // 建立实际的连接 + connection.connect(); + // 定义 BufferedReader输入流来读取URL的响应 + in = new BufferedReader(new InputStreamReader( + connection.getInputStream(), "utf-8")); + String line; + while ((line = in.readLine()) != null) { + requestResult.append(line); + } + } + // 使用finally块来关闭输入流 + catch (MalformedURLException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + if (in != null) { + in.close(); + } + } catch (Exception e2) { + e2.printStackTrace(); + } + } + return requestResult.toString(); + } +} diff --git a/jero-boot/jero-boot-module-system/src/main/java/com/jero/modules/opensso/controller/SSOLoginController.java b/jero-boot/jero-boot-module-system/src/main/java/com/jero/modules/opensso/controller/SSOLoginController.java new file mode 100644 index 000000000..28e694770 --- /dev/null +++ b/jero-boot/jero-boot-module-system/src/main/java/com/jero/modules/opensso/controller/SSOLoginController.java @@ -0,0 +1,205 @@ +package com.jero.modules.opensso.controller; + +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.jero.common.api.vo.Result; +import com.jero.common.aspect.annotation.AutoLog; +import com.jero.common.constant.CommonConstant; +import com.jero.common.system.api.ISysBaseAPI; +import com.jero.common.system.util.JwtUtil; +import com.jero.common.system.vo.LoginUser; +import com.jero.common.util.RedisUtil; +import com.jero.common.util.oConvertUtils; +import com.jero.modules.base.service.BaseCommonService; +import com.jero.modules.opensso.URLRequestResultUtil; +import com.jero.modules.system.entity.SysDepart; +import com.jero.modules.system.entity.SysUser; +import com.jero.modules.system.service.ISysDepartService; +import com.jero.modules.system.service.ISysDictService; +import com.jero.modules.system.service.ISysLogService; +import com.jero.modules.system.service.ISysUserService; +import com.jero.modules.system.util.StringUtils; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.net.URLEncoder; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @Author: liyawei + * @Description: + * @Date: Created in 11:19 2022/3/17 + */ +@RestController +@RequestMapping("/opensso") +@Api(tags="单点登录") +@Slf4j +public class SSOLoginController { + @Autowired + private ISysUserService sysUserService; + @Autowired + private ISysBaseAPI sysBaseAPI; + @Autowired + private ISysLogService logService; + @Autowired + private RedisUtil redisUtil; + @Autowired + private ISysDepartService sysDepartService; + @Autowired + private ISysDictService sysDictService; + @Resource + private BaseCommonService baseCommonService; + @Autowired + private RestTemplate restTemplate; + + private static final String BASE_CHECK_CODES = "qwertyuiplkjhgfdsazxcvbnmQWERTYUPLKJHGFDSAZXCVBNM1234567890"; + //密码登录错误的次数前缀 + public static final String RETRY_LOGIN_PREFIX = "login:retryLoginCount_"; + //密码登录错误的最大限制次数 + public static final int RETRY_LOGIN_MAX_COUNT = 5; + + private String accessTokenUrl = "https://signin-test.nio.com/oauth2/accessToken"; + private String profileUrl = "https://signin-test.nio.com/oauth2/profile"; + private String clientId = "100679"; + private String clientSecret = "CDf2D9404C6ac1B0f7c3e3845ae0282a"; + @Value("${opensso.redirectUri}") + private String redirectUri; + + @AutoLog(value = "跳转至认证中心") + @ApiOperation(value = "跳转至认证中心", notes = "跳转至认证中心") + @GetMapping(value = "/ssoAuth") + public void ssoAuth(HttpServletRequest request, HttpServletResponse response){ + String callbackUri = "http%3A%2F%2F139.9.235.66%3A8008%2Fjero-boot%2Fopensso%2Fcallback"; + String authUrl = "https://signin-test.nio.com/oauth2/authorize" +"?client_id=" + clientId + + "&redirect_uri=" + redirectUri + "&response_type=code"; + try { + response.sendRedirect(authUrl); + } catch (IOException e) { + log.error(e.getMessage(), e); + } + } + //https://signin-test.nio.com/oauth2/authorize?client_id=100679&redirect_uri=http%3A%2F%2F139.9.235.66%3A8008%2Fjero-boot%2Fopensso%2Fcallback&response_type=code + + @AutoLog(value = "单点登录回调") + @ApiOperation(value = "单点登录回调", notes = "单点登录回调") + @GetMapping(value = "/callback") + public Result callback(@RequestParam(value = "code", required = false) String code, + HttpServletRequest request, HttpServletResponse response) throws IOException { + Result result = new Result(); + // 获取access_token + String getAccessTokenUrl = accessTokenUrl + "?client_id=" + clientId + "&client_secret=" + + clientSecret + "&redirect_uri=" + redirectUri + "&code=" + URLEncoder.encode(code, "utf-8"); + log.info("access_token_url:" + getAccessTokenUrl); + Map headerMapToken = new HashMap<>(); + headerMapToken.put("Content-Type", "text/html;charset=utf-8"); +// String accessTokenResult = HttpRequestUtil.getResponseOfGET(accessTokenUrl, headerMapToken); + String accessTokenResult = URLRequestResultUtil.getProxyRequestResult(accessTokenUrl); + log.info("获取access_token返回结果:" + accessTokenResult); + // 返回结果:access_token=2.0N6OFCARTH7MRCVPSENQONSA67WGHV4FDR25TSHFCCXI6FA3NRVAA----&expires=602405 + if(StringUtils.isEmpty(accessTokenResult) || !accessTokenResult.contains("access_token")){ + return Result.error("【单点登录】获取access_token失败"); + } + int start = accessTokenResult.indexOf("="); + int end = accessTokenResult.indexOf("&"); + String accessToken = accessTokenResult.substring(start+1, end); + + //https://signin-test.nio.com/oauth2/profile?access_token=2.0N6OFCARTH7MRCVPSENQONSA67WGHV4FDR25TSHFCCXI6FA3NRVAA---- + //获取登录用户 + String getProfileUrl = profileUrl + "?access_token=" + URLEncoder.encode(accessToken, "utf-8"); + log.info("profile_url:" + getProfileUrl); + Map headerMapProfile = new HashMap<>(); + headerMapProfile.put("Content-Type", "application/json; charset=utf-8"); +// String profileResult = HttpRequestUtil.getResponseOfGET(getProfileUrl, headerMapProfile); + String profileResult = URLRequestResultUtil.getProxyRequestResult(getProfileUrl); + log.info("获取profile返回结果:" + profileResult); + // 返回结果:{ id: "xuetao.li3.o", attributes: [{workNo: "CW19057"},{account_id: ""},{user_name: "xuetao.li3.o"},{email: "xuetao.li3.o@nio.com"}]} + JSONObject userThirdIdJson = JSONObject.parseObject(profileResult); + if(ObjectUtil.isEmpty(userThirdIdJson) || !userThirdIdJson.containsKey("id")){ + return Result.error("【单点登录】获取用户profile失败"); + } + String userThirdId = userThirdIdJson.getString("id"); + String username = userThirdId; + + //1. 校验用户是否有效 + //update-begin-author:wangshuai date:20200601 for: 登录代码验证用户是否注销bug,if条件永远为false + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(SysUser::getUsername,username); + SysUser sysUser = sysUserService.getOne(queryWrapper); + //update-end-author:wangshuai date:20200601 for: 登录代码验证用户是否注销bug,if条件永远为false + result = sysUserService.checkUserIsEffective(sysUser); + if(!result.isSuccess()) { + return result; + } + + //登录成功,清除错误登录次数 + redisUtil.del(RETRY_LOGIN_PREFIX + username); + + //用户登录信息 + userInfo(sysUser, result); + //update-begin--Author:wangshuai Date:20200714 for:登录日志没有记录人员 + LoginUser loginUser = new LoginUser(); + BeanUtils.copyProperties(sysUser, loginUser); + baseCommonService.addLog("用户名: " + username + ",登录成功!", CommonConstant.LOG_TYPE_1, null,loginUser); + //update-end--Author:wangshuai Date:20200714 for:登录日志没有记录人员 + return result; + } + + /** + * 用户信息 + * + * @param sysUser + * @param result + * @return + */ + private Result userInfo(SysUser sysUser, Result result) { + String syspassword = sysUser.getPassword(); + String username = sysUser.getUsername(); + // 生成token + String token = JwtUtil.sign(username, syspassword); + // 设置token缓存有效时间 + redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token); + redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME*2 / 1000); + + // 获取用户部门信息 + JSONObject obj = new JSONObject(); + List departs = sysDepartService.queryUserDeparts(sysUser.getId()); + obj.put("departs", departs); + if (departs == null || departs.size() == 0) { + obj.put("multi_depart", 0); + } else if (departs.size() == 1) { + sysUserService.updateUserDepart(username, departs.get(0).getOrgCode()); + obj.put("multi_depart", 1); + } else { + //查询当前是否有登录部门 + // update-begin--Author:wangshuai Date:20200805 for:如果用戶为选择部门,数据库为存在上一次登录部门,则取一条存进去 + SysUser sysUserById = sysUserService.getById(sysUser.getId()); + if(oConvertUtils.isEmpty(sysUserById.getOrgCode())){ + sysUserService.updateUserDepart(username, departs.get(0).getOrgCode()); + } + // update-end--Author:wangshuai Date:20200805 for:如果用戶为选择部门,数据库为存在上一次登录部门,则取一条存进去 + obj.put("multi_depart", 2); + } + obj.put("token", token); + obj.put("userInfo", sysUser); + obj.put("sysAllDictItems", sysDictService.queryAllDictItems()); + result.setResult(obj); + result.success("登录成功"); + return result; + } +} diff --git a/jero-boot/jero-boot-single-startup/src/main/resources/application-dev.yml b/jero-boot/jero-boot-single-startup/src/main/resources/application-dev.yml index 6ae1936ec..2d2051327 100644 --- a/jero-boot/jero-boot-single-startup/src/main/resources/application-dev.yml +++ b/jero-boot/jero-boot-single-startup/src/main/resources/application-dev.yml @@ -376,3 +376,5 @@ Feishu: batchSendMessageUrl: https://open.feishu.cn/open-apis/message/v4/batch_send/ local-tool: uri: http://139.9.235.66:9022 +opensso: + redirectUri: http%3A%2F%2F139.9.235.66%3A8008%2Fjero-boot%2Fopensso%2Fcallback