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

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


前言

现在是: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("接口请求出错");
    }
  }
}

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

目录
相关文章
|
7天前
|
Web App开发 编解码 Java
B/S基层卫生健康云HIS医院管理系统源码 SaaS模式 、Springboot框架
基层卫生健康云HIS系统采用云端SaaS服务的方式提供,使用用户通过浏览器即能访问,无需关注系统的部署、维护、升级等问题,系统充分考虑了模板化、配置化、智能化、扩展化等设计方法,覆盖了基层医疗机构的主要工作流程,能够与监管系统有序对接,并能满足未来系统扩展的需要。
33 4
|
8天前
|
小程序 JavaScript Java
基于SpringBoot+Vue+uniapp微信小程序的校园水电费管理微信小程序的详细设计和实现
基于SpringBoot+Vue+uniapp微信小程序的校园水电费管理微信小程序的详细设计和实现
30 0
|
19天前
|
安全 数据安全/隐私保护
Springboot+Spring security +jwt认证+动态授权
Springboot+Spring security +jwt认证+动态授权
|
11天前
|
存储 数据可视化 安全
Java全套智慧校园系统源码springboot+elmentui +Quartz可视化校园管理平台系统源码 建设智慧校园的5大关键技术
智慧校园指的是以物联网为基础的智慧化的校园工作、学习和生活一体化环境,这个一体化环境以各种应用服务系统为载体,将教学、科研、管理和校园生活进行充分融合。无处不在的网络学习、融合创新的网络科研、透明高效的校务治理、丰富多彩的校园文化、方便周到的校园生活。简而言之,“要做一个安全、稳定、环保、节能的校园。
37 6
|
13天前
|
消息中间件 运维 供应链
springboot区域云HIS医院信息综合管理平台源码
云HIS系统分为两个大的系统,一个是基层卫生健康云综合管理系统,另一个是基层卫生健康云业务系统。基层卫生健康云综合管理系统由运营商、开发商和监管机构使用,用来进行运营管理、运维管理和综合监管。基层卫生健康云业务系统由基层医院使用,用来支撑医院各类业务运转。
21 2
|
1月前
|
前端开发 JavaScript Java
springboot+vue实现用户统一认证、管理-前端实现
springboot+vue实现用户统一认证、管理-前端实现
27 0
|
1月前
|
前端开发 JavaScript Java
springboot实现用户统一认证、管理-前端实现
springboot实现用户统一认证、管理-前端实现
14 0
|
1月前
|
前端开发 JavaScript Java
springboot实现用户统一认证、管理
springboot实现用户统一认证、管理
16 0
|
1月前
|
Kubernetes Cloud Native Devops
云原生技术落地实现之二KubeSphere DevOps 系统在 Kubernetes 集群上实现springboot项目的自动部署和管理 CI/CD (2/2)
云原生技术落地实现之二KubeSphere DevOps 系统在 Kubernetes 集群上实现springboot项目的自动部署和管理 CI/CD (2/2)
51 1
|
监控 Java
SpringBoot学习笔记-16:第十六章-SpringBoot 与监控管理
SpringBoot学习笔记-16:第十六章-SpringBoot 与监控管理
88 0