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

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

相关文章
|
25天前
|
安全 Java 数据库
安全无忧!在 Spring Boot 3.3 中轻松实现 TOTP 双因素认证
【10月更文挑战第8天】在现代应用程序开发中,安全性是一个不可忽视的重要环节。随着技术的发展,双因素认证(2FA)已经成为增强应用安全性的重要手段之一。本文将详细介绍如何在 Spring Boot 3.3 中实现基于时间的一次性密码(TOTP)双因素认证,让你的应用安全无忧。
58 5
|
3月前
|
SQL Java 测试技术
在Spring boot中 使用JWT和过滤器实现登录认证
在Spring boot中 使用JWT和过滤器实现登录认证
207 0
|
1月前
|
安全 Java 关系型数据库
springboot整合springsecurity,从数据库中认证
本文介绍了如何在SpringBoot应用中整合Spring Security,并从数据库中进行用户认证的完整步骤,包括依赖配置、数据库表创建、用户实体和仓库接口、用户详情服务类、安全配置类、控制器类以及数据库初始化器的实现。
82 3
springboot整合springsecurity,从数据库中认证
|
26天前
|
NoSQL Java Redis
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。
这篇文章介绍了如何使用Spring Boot整合Apache Shiro框架进行后端开发,包括认证和授权流程,并使用Redis存储Token以及MD5加密用户密码。
22 0
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。
|
3月前
|
消息中间件 安全 Java
Spring Boot 基于 SCRAM 认证集成 Kafka 的详解
【8月更文挑战第4天】本文详解Spring Boot结合SCRAM认证集成Kafka的过程。SCRAM为Kafka提供安全身份验证。首先确认Kafka服务已启用SCRAM,并准备认证凭据。接着,在`pom.xml`添加`spring-kafka`依赖,并在`application.properties`中配置Kafka属性,包括SASL_SSL协议与SCRAM-SHA-256机制。创建生产者与消费者类以实现消息的发送与接收功能。最后,通过实际消息传递测试集成效果与认证机制的有效性。
129 4
|
4月前
|
JavaScript Java 测试技术
基于SpringBoot+Vue个人健康管理网站设计和实现(源码+LW+部署讲解)
基于SpringBoot+Vue个人健康管理网站设计和实现(源码+LW+部署讲解)
70 7
|
4月前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的宠物饲养管理APP的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的宠物饲养管理APP的详细设计和实现(源码+lw+部署文档+讲解等)
|
4月前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的二手家电管理平台的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的二手家电管理平台的详细设计和实现(源码+lw+部署文档+讲解等)
|
4月前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的个人健康管理网站的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的个人健康管理网站的详细设计和实现(源码+lw+部署文档+讲解等)
|
4月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的宠物饲养管理APP附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的宠物饲养管理APP附带文章源码部署视频讲解等
32 1