springboot实现用户统一认证、管理(单点登录)

 muxiongxiong   2022-05-25 22:01   342 人阅读  0 条评论

大家好,我是雄雄,欢迎关注微信公众号:雄雄的小课堂

前言

现在是:2022年5月25日13:44:16

最近和模拟登录杠上了,这不,又来了个需求,还是以这个技术点入手的。
需求大概是这样的:为了统一管理系统的用户,上游平台做了个统一认证平台,所有用户进入子系统只有一个入口,即:上游平台登录入口,新用户也是上游平台进行添加;子系统的用户登录和注册模块都屏蔽掉。

设计技能点

  1. 前端:Vue
  2. 后端:springboot (bladex框架)
  3. 数据库:mysql 5.7及以上

实现思路

  1. 上游平台通过回调接口,将用户和组织机构同步至子系统
  2. 上游平台通过url在地址栏中挂sessionid的方式访问子系统的登录页面
  3. 子系统检地址栏中是否有sessionid,如果有,则拿着sessionid去上游系统获取用户信息,然后在子系统中拿着用户信息自动登录
  4. 如果地址栏中没有sessionid,则需要带着子系统的登录地址,重定向至上游平台(上游平台怎么处理的,我就不知道了,我猜测,如果用户未在上游平台登录,则不带sessionid来的子系统,如果登录了则会带着过来。所以重定向到上游平台时,应该是让用户重新进行登录的)
  5. 当用户点击退出时,清除子系统的用户登录状态的同时还需要清除上游系统,且重定向至上游平台的登录页面

代码实现

回调接口实现了两个功能:

  • 同步组织机构
  • 同步用户信息

为了后期维护方便,前后端所有调用外部的地址,从接口中获取数据等均单独提取出来了,这样也能更好的实现复用。

  1. 统一接口管理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";


	}

  1. 公用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);

	}


  1. 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();
		}


	}

先实现功能,在做优化~

  1. 控制器中的实现方法:
	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("接口请求出错");
		}
	}

}

整个后台的代码基本上就这些,基本上没啥难度,就是光操作的调用接口就可以了,主要麻烦点的是在前端,明天分享一下前端的实现。

本文地址:http://xn--ypzn79ca.com/?id=1396
版权声明:本文为原创文章,版权归 muxiongxiong 所有,欢迎分享本文,转载请保留出处!

 发表评论


表情

还没有留言,还不快点抢沙发?