”
前言
现在是:2022年5月25日13:44:16
最近和模拟登录杠上了,这不,又来了个需求,还是以这个技术点入手的。需求大概是这样的:为了统一管理系统的用户,上游平台做了个统一认证平台,所有用户进入子系统只有一个入口,即:上游平台登录入口,新用户也是上游平台进行添加;子系统的用户登录和注册模块都屏蔽掉。
设计技能点
- 前端:Vue
- 后端:springboot (bladex框架)
- 数据库:mysql 5.7及以上
实现思路
- 上游平台通过回调接口,将用户和组织机构同步至子系统
- 上游平台通过
url
在地址栏中挂sessionid
的方式访问子系统的登录页面 - 子系统检地址栏中是否有
sessionid
,如果有,则拿着sessionid
去上游系统获取用户信息,然后在子系统中拿着用户信息自动登录 - 如果地址栏中没有
sessionid
,则需要带着子系统的登录地址,重定向至上游平台(上游平台怎么处理的,我就不知道了,我猜测,如果用户未在上游平台登录,则不带sessionid
来的子系统,如果登录了则会带着过来。所以重定向到上游平台时,应该是让用户重新进行登录的) - 当用户点击退出时,清除子系统的用户登录状态的同时还需要清除上游系统,且重定向至上游平台的登录页面
代码实现
回调接口实现了两个功能:
- 同步组织机构
- 同步用户信息
为了后期维护方便,前后端所有调用外部的地址,从接口中获取数据等均单独提取出来了,这样也能更好的实现复用。
- 统一接口管理
SsoLoginConstant
package org.springblade.modules.system.util; /** * @Description: TODO * @author: 穆雄雄 * @date: 2022/5/17 下午 2:40 * 放一些公共的常量 * @Return: */ public interface SsoLoginConstant { /** * 统一认证平台的地址 */ public final static String SSO_URL = "http://************"; /** * 登录鉴权 */ public final static String CHECKLOGIN_URL =SSO_URL+ "/check_login"; /** * 查询平台用户信息 */ public final static String QUERYUSER_URL =SSO_URL+ "/get_user"; /** * 查询平台组织机构信息 */ public final static String QUERYDEPARTMENT_URL =SSO_URL+ "/get_department"; /** * 退出系统 */ public final static String APILOGOUT_URL =SSO_URL+ "/api_logout"; }
- 公用
Service
层接口:
package org.springblade.modules.system.service; import org.springblade.core.tool.api.R; import org.springframework.web.bind.annotation.RequestBody; /** * @author: muxiongxiong * @date: 2022年05月21日 上午 8:41 * 公众号:雄雄的小课堂 * 博客:https://blog.csdn.net/qq_34137397 * 个人站:http://www.穆雄雄.com * 个人站:http://www.muxiongxiong.cn * @Description: 类的描述:单点登录业务层接口 */ public interface ISsoLoginService { /** * @Description: 登录鉴权 * @author: 穆雄雄 * @date: 2022/5/21 上午 8:54 No such property: code for class: Script1 * @Return: */ String checkLogin(String ssoSessionKey); /** * @Description: 查询平台用户信息 * @author: 穆雄雄 * @date: 2022/5/21 上午 8:42 * 查询平台用户信息 * @Return: */ String getUser(String projectKey); /** * @Description: 查询平台组织机构信息 * @author: 穆雄雄 * @date: 2022/5/21 上午 8:50 * 查询平台用户信息 * @Return: java.lang.String */ String getDepartment(String projectKey); /** * @Description: 上传平台用户信息 * @author: 穆雄雄 * @date: 2022/5/21 上午 9:24 * @Return: java.lang.String */ R pullUserInfo(@RequestBody String val); /** * @Description: 退出 * @author: 穆雄雄 * @date: 2022年5月25日15:34:58 No such property: code for class: Script1 * @Return: */ String apiLogout(String ssoSessionKey); }
Service
层实现类:
package org.springblade.modules.system.service.impl; import cn.hutool.http.HttpUtil; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.commons.lang.StringUtils; import org.springblade.core.tool.api.R; import org.springblade.modules.system.entity.Dept; import org.springblade.modules.system.entity.User; import org.springblade.modules.system.entity.UserService; import org.springblade.modules.system.service.IDeptService; import org.springblade.modules.system.service.ISsoLoginService; import org.springblade.modules.system.service.IUserService; import org.springblade.modules.system.util.SsoLoginConstant; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.HashMap; import java.util.Map; /** * @author: muxiongxiong * @date: 2022年05月21日 上午 8:51 * 公众号:雄雄的小课堂 * 博客:https://blog.csdn.net/qq_34137397 * 个人站:http://www.穆雄雄.com * 个人站:http://www.muxiongxiong.cn * @Description: 类的描述 */ @Service public class SsoLoginServiceImpl implements ISsoLoginService { @Autowired private IUserService userService; @Autowired private IDeptService deptService; /** * 登录鉴权 */ @Override public String checkLogin(String ssoSessionKey) { JSONObject jsonObjectResult = new JSONObject(); //请求接口地址 String url = SsoLoginConstant.CHECKLOGIN_URL; Map<String, Object> paramMap = new HashMap<String, Object>(); paramMap.put("ssoSessionKey", ssoSessionKey); try { String body = HttpUtil.createPost(url).form(paramMap).execute().body(); if (StringUtils.isBlank(body)) { jsonObjectResult.put("code", 500); jsonObjectResult.put("msg", "请求失败"); jsonObjectResult.put("data", ""); jsonObjectResult.put("status", false); return jsonObjectResult.toJSONString(); } JSONObject obj = JSONObject.parseObject(body); if (obj == null) { jsonObjectResult.put("code", 500); jsonObjectResult.put("msg", "请求失败"); jsonObjectResult.put("data", ""); jsonObjectResult.put("status", false); return jsonObjectResult.toJSONString(); } String code = obj.get("code").toString(); if ("200".equals(code)) { jsonObjectResult.put("code", 200); jsonObjectResult.put("msg", "请求成功"); jsonObjectResult.put("data", obj.get("data")); jsonObjectResult.put("status", false); return jsonObjectResult.toJSONString(); }else{ jsonObjectResult.put("code", 500); jsonObjectResult.put("msg", "请求失败"); jsonObjectResult.put("data", ""); jsonObjectResult.put("status", false); return jsonObjectResult.toJSONString(); } } catch (Exception e) { e.printStackTrace(); } return jsonObjectResult.toJSONString(); } /** * 获取平台用户 */ @Override public String getUser(String projectKey) { JSONObject jsonObjectResult = new JSONObject(); //请求接口地址 String url = SsoLoginConstant.QUERYUSER_URL; Map<String, Object> paramMap = new HashMap<String, Object>(); paramMap.put("projectKey", projectKey); try { String body = HttpUtil.createGet(url).form(paramMap).execute().body(); if (StringUtils.isBlank(body)) { jsonObjectResult.put("code", 500); jsonObjectResult.put("msg", "请求失败"); jsonObjectResult.put("data", ""); jsonObjectResult.put("status", false); return jsonObjectResult.toJSONString(); } JSONObject obj = JSONObject.parseObject(body); if (obj == null) { jsonObjectResult.put("code", 500); jsonObjectResult.put("msg", "请求失败"); jsonObjectResult.put("data", ""); jsonObjectResult.put("status", false); return jsonObjectResult.toJSONString(); } String code = obj.get("code").toString(); if ("200".equals(code)) { jsonObjectResult.put("code", 200); jsonObjectResult.put("msg", "请求成功"); jsonObjectResult.put("data", obj.get("data")); jsonObjectResult.put("status", false); return jsonObjectResult.toJSONString(); } } catch (Exception e) { e.printStackTrace(); } return jsonObjectResult.toJSONString(); } /** * 获取组织机构 */ @Override public String getDepartment(String projectKey) { JSONObject jsonObjectResult = new JSONObject(); //请求接口地址 String url = SsoLoginConstant.QUERYDEPARTMENT_URL; Map<String, Object> paramMap = new HashMap<String, Object>(); paramMap.put("projectKey", projectKey); try { String body = HttpUtil.createGet(url).form(paramMap).execute().body(); if (StringUtils.isBlank(body)) { jsonObjectResult.put("code", 500); jsonObjectResult.put("msg", "请求失败"); jsonObjectResult.put("data", ""); jsonObjectResult.put("status", false); return jsonObjectResult.toJSONString(); } JSONObject obj = JSONObject.parseObject(body); if (obj == null) { jsonObjectResult.put("code", 500); jsonObjectResult.put("msg", "请求失败"); jsonObjectResult.put("data", ""); jsonObjectResult.put("status", false); return jsonObjectResult.toJSONString(); } String code = obj.get("code").toString(); if ("200".equals(code)) { jsonObjectResult.put("code", 200); jsonObjectResult.put("msg", "请求成功"); jsonObjectResult.put("data", obj.get("data")); jsonObjectResult.put("status", false); return jsonObjectResult.toJSONString(); } } catch (Exception e) { e.printStackTrace(); } return jsonObjectResult.toJSONString(); } /** * 上传平台用户信息 * @param val * @return */ @Override public R pullUserInfo(String val) { //转换成集合类型 JSONArray userListArray = JSONArray.parseArray(val); boolean flag = false; for (Object o : userListArray) { JSONObject jsonObject = (JSONObject) o; User user = new User(); //add表示添加 //update表示更新 //delete表示删除 String operate = jsonObject.getString("operate"); //固定标识 String type = jsonObject.getString("type"); JSONObject dataObject = jsonObject.getJSONObject("data"); if (type.equals("sso_user")) { Long id = dataObject.getLong("id"); //用户账号 String account = dataObject.getString("account"); //用户名称 String name = dataObject.getString("name"); //所属部门 String departmentId = dataObject.getString("departmentId"); //手机号 String mobile = dataObject.getString("mobile"); //用户角色,1表示管理者,2表示使用者 String isManager = dataObject.getString("isManager"); //应用编号 String project = dataObject.getString("project"); //添加用户 user.setId(id); user.setPhone(mobile); user.setTenantId("000000"); user.setCode(""); if(isManager.equals("1")){ //管理员 user.setRoleId("1529303109787967490"); }else if(isManager.equals("2")){ //一般用户 user.setRoleId("1529302965017370625"); }else{ //会员(这个地方不会执行到,只要isManager不等于null) user.setRoleId("1355058724514836481"); } user.setUserType(Integer.parseInt(isManager)); user.setAccount(account); //密码是123456 user.setPassword("10470c3b4b1fed12c3baac014be15fac67c6e815"); user.setName(name); user.setRealName(name); user.setDeptId(departmentId); user.setStatus(1); //证明是那边过来的用户 user.setRemark(type); switch (operate) { case "add": flag = userService.save(user); break; case "update": flag = userService.updateUser(user); break; case "delete": flag = userService.updateById(user); break; default: break; } } else if (type.equals("sso_department")) { Dept dept = new Dept(); Long id = dataObject.getLong("id"); //用户账号 String title = dataObject.getString("title"); //父级企业ID String parentId = dataObject.getString("parentId"); //企业等级 String level = dataObject.getString("level"); //排序 String sort = dataObject.getString("sort"); //用户角色,1表示管理者,2表示使用者 String isManager = dataObject.getString("isManager"); //业务管路员ID String manager = dataObject.getString("manager"); //业务管路员ID String project = dataObject.getString("project"); dept.setId(id); dept.setDeptName(title); dept.setTenantId("000000"); dept.setParentId(Long.parseLong(parentId)); dept.setAncestors("0," + parentId); dept.setDeptCategory(3); dept.setFullName(title); dept.setSort(Integer.parseInt(sort)); dept.setRemark(type); dept.setIsDeleted(0); switch (operate) { case "add": flag = deptService.save(dept); break; case "update": flag = deptService.updateById(dept); break; case "delete": flag = deptService.removeDept(id.toString()); break; default: break; } } } return R.status(flag); } /** * 退出 * @param ssoSessionKey * @return */ @Override public String apiLogout(String ssoSessionKey) { JSONObject jsonObjectResult = new JSONObject(); //请求接口地址 String url = SsoLoginConstant.APILOGOUT_URL; Map<String, Object> paramMap = new HashMap<String, Object>(); paramMap.put("ssoSessionKey", ssoSessionKey); try { String body = HttpUtil.createPost(url).form(paramMap).execute().body(); if (StringUtils.isBlank(body)) { jsonObjectResult.put("code", 500); jsonObjectResult.put("msg", "请求失败"); jsonObjectResult.put("data", ""); jsonObjectResult.put("status", false); return jsonObjectResult.toJSONString(); } JSONObject obj = JSONObject.parseObject(body); if (obj == null) { jsonObjectResult.put("code", 500); jsonObjectResult.put("msg", "请求失败"); jsonObjectResult.put("data", ""); jsonObjectResult.put("status", false); return jsonObjectResult.toJSONString(); } String code = obj.get("code").toString(); if ("200".equals(code)) { jsonObjectResult.put("code", 200); jsonObjectResult.put("msg", "请求成功"); jsonObjectResult.put("data", obj.get("data")); jsonObjectResult.put("status", false); return jsonObjectResult.toJSONString(); }else{ jsonObjectResult.put("code", 500); jsonObjectResult.put("msg", "请求失败"); jsonObjectResult.put("data", ""); jsonObjectResult.put("status", false); return jsonObjectResult.toJSONString(); } } catch (Exception e) { e.printStackTrace(); } return jsonObjectResult.toJSONString(); } }
先实现功能,在做优化~
- 控制器中的实现方法:
package org.springblade.modules.system.controller; import cn.hutool.http.HttpUtil; import cn.hutool.json.JSONUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.metadata.IPage; import io.swagger.annotations.Api; import lombok.AllArgsConstructor; import org.apache.commons.lang.StringUtils; import org.springblade.common.constant.TrainingSchemeConstant; import org.springblade.core.mp.support.Condition; import org.springblade.core.mp.support.Query; import org.springblade.core.tool.api.R; import org.springblade.core.tool.utils.Func; import org.springblade.modules.system.entity.User; import org.springblade.modules.system.entity.UserService; import org.springblade.modules.system.service.ISsoLoginService; import org.springblade.modules.system.service.impl.KnowledgeServiceImpl; import org.springblade.modules.system.service.impl.SsoLoginServiceImpl; import org.springblade.modules.system.service.impl.UserServiceImpl; import org.springblade.modules.system.util.SsoLoginConstant; import org.springblade.modules.system.util.TokenUtil; import org.springblade.modules.system.vo.KnowledgeVO; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import org.springframework.web.client.RestTemplate; import java.util.HashMap; import java.util.Map; @RestController @AllArgsConstructor @RequestMapping("api/sso") @Api(value = "", tags = "接口") public class ApiSsoController { private final SsoLoginServiceImpl ssoLoginService; /** * 用户信息 */ private final UserServiceImpl userService; //private final RabbitTemplate rabbitTemplate; /** * 统一认证平台向第三方平台的接口发起请求。 * 新增、修改、删除平台用户信息,将用户数据上传到我方 * * @param */ @PostMapping(value = "/pulluserinfo") public String pulluserinfo(@RequestBody String val) { JSONObject object = new JSONObject(); R r = ssoLoginService.pullUserInfo(val); if (r.getCode() == 200) { object.put("msg", "操作成功"); object.put("success", true); object.put("code", 200); } else { object.put("msg", "操作失败"); object.put("success", false); object.put("code", 500); } return object.toJSONString(); } /** * 登录鉴权 * */ @GetMapping("/check_login") public R checkLogin(String ssoSessionKey) { //拿到接口返回值 String result = ssoLoginService.checkLogin(ssoSessionKey); JSONObject jsonObject = JSON.parseObject(result); Integer code = jsonObject.getInteger("code"); if (code == 200) { //操作成功 JSONObject jsonObjectData = jsonObject.getJSONObject("data"); //拿到用户名和密码 if (jsonObjectData != null) { //将用户名传给前台,前台拿着去登陆去 String account = jsonObjectData.getString("username"); return R.data(account); } else { return R.fail("未找到该用户"); } } else { //操作失败 return R.fail("未找到该用户"); } } /** * 查询平台用户信息 * */ @GetMapping("/get_user") public String getUser(String projectKey) { return ssoLoginService.getUser(projectKey); } /** * 查询平台组织机构 * */ @GetMapping("/get_department") public String getDepartment(String projectKey) { return ssoLoginService.getDepartment(projectKey); } /** * 退出时调用 * 注销统一认证平台的用户信息 */ @GetMapping("/api_logout") public R apiLogout(String ssoSessionKey) { //拿到接口返回值 String result = ssoLoginService.apiLogout(ssoSessionKey); JSONObject jsonObject = JSON.parseObject(result); Integer code = jsonObject.getInteger("code"); if (code == 200) { return R.success("操作成功"); } else { //操作失败 return R.fail("接口请求出错"); } } }
整个后台的代码基本上就这些,基本上没啥难度,就是光操作的调用接口就可以了,主要麻烦点的是在前端,明天分享一下前端的实现。