大家好,我是雄雄,欢迎关注微信公众号:雄雄的小课堂
前言
现在是: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:54No 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:58No 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: 类的描述*/@Servicepublic class SsoLoginServiceImpl implements ISsoLoginService {@Autowiredprivate IUserService userService;@Autowiredprivate IDeptService deptService;/*** 登录鉴权*/@Overridepublic 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();}/*** 获取平台用户*/@Overridepublic 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();}/*** 获取组织机构*/@Overridepublic 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*/@Overridepublic 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);//密码是123456user.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");//父级企业IDString parentId = dataObject.getString("parentId");//企业等级String level = dataObject.getString("level");//排序String sort = dataObject.getString("sort");//用户角色,1表示管理者,2表示使用者String isManager = dataObject.getString("isManager");//业务管路员IDString manager = dataObject.getString("manager");//业务管路员IDString 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*/@Overridepublic 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("接口请求出错");}}}
整个后台的代码基本上就这些,基本上没啥难度,就是光操作的调用接口就可以了,主要麻烦点的是在前端,明天分享一下前端的实现。