轻量级 SSO 方略

news2024/11/28 8:42:32

单点登录 SSO(Single Sign On)是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。打通所有系统的账户密码,只需要记住一个就行,而且登录一个系统后,打开其他系统不需要再登录。广义的单点登录概念还涵盖了第三方登录:己方应用信任第三方应用,用户只需在第三方应用上登录一次,就可以访问己方应用。

更高阶的产品 IAM(Identity and Access Management),即“身份识别与访问管理”,具有单点登录、强大的认证管理、基于策略的集中式授权和审计、动态授权、企业可管理性等功能。参考开源项目 Keycloak。

OIDC

OIDC 是 OpenID Connect,官网介绍。

感觉 OAuth 太负盛名了,以至于后来在 OIDC 反而难以企及前辈 OAuth。倒是大家谈论比较多的是 JWT(例如https://www.cnblogs.com/lyzg/p/6132801.html),——实际谈 JWT 就是在实现 OIDC,反而 OIDC 大家不怎么爱谈!但我们要知道的是,真正诠释这些的,做点单点登录的,——是 OIDC 规范,JWT 只是 OIDC 规范下的一种 Token 协议,再说句难听的,如果 JWT 不满足或者有问题,换别的 Token 实现规则也行。

不过话说回来,OIDC 与 OAuth 看上去大体是相近,只是把应用场景稍作转换,另外就是返回 Token 的不同,OAuth 不限定 Token 具体实现如何,而 OIDC 推荐带用户信息的 JWT。所以,这么说,也不能怪人们总爱谈 JWT 而忽视 OIDC

部署

目标是部署简单,且灵活多种方式。下面是 SSO 中心的部署方式。

单独部署整合部署
部署形态WAR/JAR 包,单独进程运行JAR 包引入依赖,或源码整合
优点独立维护占资源更低

除了 SSO 中心的部署,还有客户端以 JAR 包的形式提供。

无状态设计

传统认证基于 Cookie+Session 的方式,是有状态的;单机时代问题不大,但到了集群的时候,如何同步 Session 是件麻烦的事情。另外一个方法是绑定 Session 到指定某一台机器,但这样不仅带来复杂性,而且还不能彻底解决问题。因此,渐渐有了以下分野:

  • 服务端是无状态的:服务端组件不保存会话状态。
  • 服务端是有状态的:服务端组件保存了会话状态。

我们主张服务端无状态的设计。当服务端组件不保存任何会话状态时,伸缩将比较容易,直接增加/减少物理服务器的台数即可。《Web应用中的状态(会话状态、应用状态、有状态协议、无状态协议、REST无状态约束)》这文章分析得很透彻了。

关于 Token 的设计

Token 从简单到复杂,可以采取下面几种方案。

  • 最简单的 Token,就是随机字符串,那么我们用 UUID/GUID 即可
  • 如果有验证 AuthToken 合法性需求,可以将 UserName+ 时间戳加密生成,服务端解密之后验证合法性
  • JWT。我们后面重点说 JWT

可配置

强调系统的鲁棒性,从最简单的组件到复杂的组件,均可支持,例如,缓存组件,简单点的你可以使用本地的 Servlet Session,高级一点的可以采用 Redis。

应用 App

每个想要接入OAuth 授权服务的第三方客户端都需要事先在服务端这里“备案”,这样可以更好的管理接入的第三方应用。App 多数时候与 Client 的概念是一致的。

注册应用的时候一般需要提供一些基本信息,比如应用名称、网址、logo 等。主要需要以下几个字段:

  • name:应用的名称,这个便于后台管理用的
  • client_id:每个应用客户端的 client_id 是唯一的,相当于用户名,通常是一个随机生成的字符串,client_id 可以直接写在 Javascript 或者源码页面里面
  • client_secret:这个秘钥是应用客户端和 OAuth2.0 服务端共同持有,用于鉴别请求中的身份,通常也是一个随机生成的字符串。client_secret 必须保证绝对机密,不能泄露给其他人。如果你部署的应用无法保证 client_secret 安全的话,比如Javascript 应用或者 Native APP,那么则不能使用 client_secret。一般来说,只有服务器端才可以保存 client_secret
  • redirect_uri:第三方应用的地址。Redirect URI 可以在用户授权完成之后重定向回你的应用。Redirect URI 授权服务器只会重定向用户到已经注册过的 URI,以避免一些恶意攻击

模块设计

表设计及界面设计如下

CREATE TABLE `app` (
	`id` INT(10) NOT NULL AUTO_INCREMENT COMMENT '主键 id,自增',
	`pid` INT(10) NOT NULL DEFAULT '0' COMMENT '父级 id',
	`name` VARCHAR(20) NOT NULL COMMENT '名称' COLLATE 'utf8mb4_unicode_ci',
	`content` VARCHAR(256) NULL DEFAULT NULL COMMENT '简介' COLLATE 'utf8mb4_unicode_ci',
	`client_id` VARCHAR(256) NOT NULL COMMENT '客户端 id' COLLATE 'utf8mb4_unicode_ci',
	`client_secret` VARCHAR(256) NOT NULL COMMENT '客户端秘钥' COLLATE 'utf8mb4_unicode_ci',
	`redirect_uri` VARCHAR(256) NOT NULL COMMENT '用户授权完成之后重定向回你的应用' COLLATE 'utf8mb4_unicode_ci',
	`type` VARCHAR(20) NULL DEFAULT 'MISC' COMMENT '应用类型:HTML, APP,API_SERVICE, RPC_SERVICE, MISC' COLLATE 'utf8mb4_unicode_ci',
	`logo` VARCHAR(200) NULL DEFAULT NULL COMMENT '图标' COLLATE 'utf8mb4_unicode_ci',
	`stat` TINYINT(3) NULL DEFAULT NULL COMMENT '数据字典:状态',
	`extend` TEXT NULL DEFAULT NULL COMMENT '扩展 JSON 字段' COLLATE 'utf8mb4_unicode_ci',
	`creator` VARCHAR(50) NULL DEFAULT NULL COMMENT '创建人名称(可冗余的)' COLLATE 'utf8mb4_bin',
	`creator_id` INT(10) NULL DEFAULT NULL COMMENT '创建人 id',
	`create_date` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建日期',
	`updater` VARCHAR(50) NULL DEFAULT NULL COMMENT '修改人名称(可冗余的)' COLLATE 'utf8mb4_bin',
	`updater_id` INT(10) NULL DEFAULT NULL COMMENT '修改人 id',
	`update_date` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改日期',
	PRIMARY KEY (`id`) USING BTREE,
	UNIQUE INDEX `id_UNIQUE` (`id`) USING BTREE
)
COMMENT='应用/客户端'

在这里插入图片描述

计划

抽象 App 概念,可纳入 System,利用 pid 做层级。

授权模式对比总结

本文只对前后端授权常见的授权码模式做详细介绍,其他授权模式可自行了解,这里只做简单介绍。

在这里插入图片描述

配置

用户密码的加密规则

用户密码当然不能明文保存到数据库中,因为一旦泄露密码,危害的不止系统本身,还有危害用户的切身利益(因为用户不同系统的密码可能是一样的)。那么怎么实现一个加密规则呢?

AJ-IAM 把这个问题开放出来,允许用户自定义自己的加密规则。下面是一个简单的 MD5 加盐配置例子。

/**
 * 指定密码的加密规则
 */
@Bean("passwordEncode")
Function<String, String> passwordEncode() {
    return PasswordEncoder::md5salt;
}

因为比较简单的缘故,我们并没有设计一个 Java Interface 去定义,而是一个 Lambda:Function<String, String>搞定。输入参数是明文,返回值是密文。要知道,Spring 对 Lambda 也是可以注入的。PasswordEncoder::md5salt参见:

package com.ajaxjs.user.service.business;

import com.ajaxjs.util.Digest;

/**
 * 密码加密规则
 */
public class PasswordEncoder {
    /**
     * 盐值
     */
    private static final String SALT = "@#D2s!As12";

    /**
     * 基本的密码加密
     *
     * @param psw 明文
     * @return 密文
     */
    public static String md5salt(String psw) {
        return Digest.md5(psw + SALT);
    }
}
  • 认证(Authentication),识别你是谁。即在网站上用来识别某个用户是否是注册过的合法用户。本文前半段皆在讲认证;
  • 授权(Authorization),识别你能做什么。即在网站上用来识别某个用户是否有某方面的权限。本文后半段皆在讲授权。

开源参考

  • 符节开源 JAP https://gitee.com/fujieid/jap、https://gitee.com/fujieid/jap-ids-oauthserver
  • ArkID : 企业级IDaaS/IAM平台系统
  • TopIAM 数字身份管控平台
  • 推荐七个非常实用的OAuth开源项目
  • MITREid Connect

安全考量

Insufficient Redirect URI validation: The risk of allowing to dynamically add arbitrary query parameters and fragments to the redirect_uri。这是一种 OAuth 2.0 和 OpenID Connect 1.0 实现缺陷模式,允许动态添加查询参数和片段到 redirect_uri。如果 redirect_uri 没有得到适当的验证,攻击者可以构造一个包含指向攻击者控制的服务器的 URL 的链接。这可以用来欺骗 AS 将授权代码发送给攻击者。如果用户在用户代理中打开此链接,AS 将重定向用户代理到恶意 URL。攻击者可以捕获伪造 URL 中传递的代码值,然后将其提交给 AS 令牌端点。如果您想测试 AS 是否容易受到不足的重定向 URI 验证,请使用 HTTP 拦截代理(例如 ZAP)捕获流量。启动 OAuth 流并在授权请求处暂停它。更改 redirect_uri 的值并观察响应。调查响应并确定是否接受了任意 redirect_uri 参数。如果 AS 将用户代理重定向到您指定的 redirect_uri,则 AS 未正确验证 redirect_uri。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1146109.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Unity程序技巧】Input管理器

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;Uni…

【Python 零基础入门】常用内置函数 初探

【Python 零基础入门】内容补充 1 常用内置函数 Python 简介为什么要学习内置函数数据类型和转换int(): 转为整数float(): 转为浮点数list(): 转为列表tuple(): 转换为元组set():转换为集合dict(): 创建字典: 数学运算abs(): 绝对值pow(): 幂运算round(): 四舍五入min(): 最小值…

类与面向对象

章节目录&#xff1a; 一、面向对象二、类2.1 类定义2.2 类对象2.3 self 代表类的实例&#xff0c;而非类 三、类的方法四、多继承五、方法重写六、私有属性及私有方法七、类的专有方法八、专有方法重载九、结束语 一、面向对象 Python 从设计之初就已经是一门面向对象的语言。…

【错误解决方案】ModuleNotFoundError: No module named ‘torch._six‘

1. 错误提示 在python程序中&#xff0c;试图导入一个名为torch._six的模块&#xff0c;但Python提示找不到这个模块。 错误提示&#xff1a;ModuleNotFoundError: No module named torch._six 2. 解决方案 出现这个错误可能是因为你使用的PyTorch版本和你的代码不兼容。在某…

MySQL实战1

文章目录 主要内容一.墨西哥和美国第三高峰1.准备工作代码如下&#xff08;示例&#xff09;: 2.目标3.实现代码如下&#xff08;示例&#xff09;: 4.相似例子代码如下&#xff08;示例&#xff09;: 二.用latest_event查找当前打开的页数1.准备工作代码如下&#xff08;示例&…

nrf52832 开发板入手笔记:J-Flash 蓝牙协议栈烧写

前言 nrf52832 想要开启 蓝牙功能&#xff0c;比如蓝牙主从机功能&#xff0c;需要额外烧写 蓝牙协议栈的固件&#xff1a;softdevice&#xff0c;换句话说&#xff0c;蓝牙协议栈等代码是不开放的&#xff0c;只提供一个 二进制文件。 也就是 nrf52832 Flash 与 RAM 要分区了…

Linux学习第26天:异步通知驱动开发: 主动

Linux版本号4.1.15 芯片I.MX6ULL 大叔学Linux 品人间百味 思文短情长 在正式开启今天的学习前&#xff0c;讲一讲为什么标题中加入了【主动】俩字。之前学习的阻塞和非阻塞IO&#xff0c;都是在被动的接受应用程序的操作。而今天的学…

MyBatis-Plus 实战教程四 idea插件

文章目录 插件功能分页插件配置分页插件分页API 通用分页实体实体开发接口改造PageQuery实体改造PageDTO实体 仓库地址 插件功能 MybatisPlus提供了很多的插件功能&#xff0c;进一步拓展其功能。目前已有的插件有&#xff1a; PaginationInnerInterceptor&#xff1a;自动分…

中微爱芯74逻辑兼容替代TI/ON/NXP工规品质型号全

这里写自定义目录标题 工业级型号全产品线概述![在这里插入图片描述](https://img-blog.csdnimg.cn/097ef810b2234f07b0c0c1e962a73761.png)批量应用行业头部客户兼容替代封装对照逻辑参数对比电平转换系列型号对照HC/HCT 系列型号对照AHC/AHCT 系列型号对照LV/LVC 系列型号对照…

【ARMv8 SIMD和浮点指令编程】NEON 通用数据处理指令——复制、反转、提取、转置...

NEON 通用数据处理指令包括以下指令(不限于): • DUP 将标量复制到向量的所有向量线。 • EXT 提取。 • REV16、REV32、REV64 反转向量中的元素。 • TBL、TBX 向量表查找。 • TRN 向量转置。 • UZP、ZIP 向量交叉存取和反向交叉存取。 1 DUP (element) 将…

无线电编码和记录和静音检测器 PlayOutONE LiveStream 5.0

直播编码器&#xff0c;随处流式传输。LiveStream 应用程序的多色图案屏幕截图&#xff0c;显示一波进入&#xff0c;四路流出来&#xff0c;LiveStream是一站式应用程序&#xff0c;可让您的电台在需要的地方输出。 对音频进行编码以进行流式传输&#xff0c;使用您最喜欢的V…

Megatron-LM GPT 源码分析(三) Pipeline Parallel分析

引言 本文接着上一篇【Megatron-LM GPT 源码分析&#xff08;二&#xff09; Sequence Parallel分析】&#xff0c;基于开源代码 GitHub - NVIDIA/Megatron-LM: Ongoing research training transformer models at scale &#xff0c;通过GPT的模型运行示例&#xff0c;从三个维…

【鸿蒙软件开发】ArkTS基础组件之TextClock(时间显示文本)、TextPicker(滑动选择文本)

文章目录 前言一、TextClock1.1 子组件1.2 接口参数TextClockController 1.3 属性1.4 事件1.5 示例代码 二、TextPicker2.1 子组件2.2 接口参数 2.3 属性2.4 事件2.5 示例代码 总结 前言 TextClock组件:通过文本将当前系统时间显示在设备上。支持不同时区的时间显示&#xff0…

MySQL实战2

文章目录 主要内容一.回访用户1.准备工作代码如下&#xff08;示例&#xff09;: 2.目标3.实现代码如下&#xff08;示例&#xff09;: 二.如何找到每个人每月消费的最大天数1.准备工作代码如下&#xff08;示例&#xff09;: 2.目标3.实现代码如下&#xff08;示例&#xff09…

Pandas时间序列、时间戳对象、类型转换、时间序列提取、筛选、重采样、窗口滑动

时间序列数据是指在时间间隔不变的情况下收集的时间点数据&#xff0c;可以用来分析事物的长期发展趋势&#xff0c;并对未来进行预测。 date_range()方法及参数 pandas.date_range(startNone, endNone, periodsNone, freqNone, tzNone, normalizeFalse, nameNone, inclusive‘…

08.K8S高可用方案

K8S高可用方案 1、高可用部署方式 官方提供两种高可用实现方式: 堆叠etcd 拓扑,其中 etcd 节点与控制平面节点共存;外部 etcd 节点,其中 etcd 与控制平面在不同的节点上运行;1.1、堆叠 etcd 拓扑 主要特点: 每个 master 节点上运行一个 apiserver 和 etcd, etcd 只与本…

Spring Security: 整体架构

Filter Spring Security 是基于 Sevlet Filter 实现的。下面是一次 Http 请求从 client 出发&#xff0c;与 Servlet 交互的图&#xff1a; 当客户端发送一个请求到应用&#xff0c;容器会创建一个 FilterChain&#xff0c;FilterChain 中包含多个 Filter 和 Servlet。这些 Fi…

C#,数值计算——分类与推理,基座向量机的 Svmgenkernel的计算方法与源程序

1 文本格式 using System; namespace Legalsoft.Truffer { public abstract class Svmgenkernel { public int m { get; set; } public int kcalls { get; set; } public double[,] ker { get; set; } public double[] y { get; set…

构建第二大脑#知识库使用指南

fortelabs.com/blog/basboverview 《构建第二大脑&#xff1a;入门指南》提到一个步骤&#xff1a; 通过策划和管理您的个人信息流来减轻压力和“信息过载”创建一个内心平静的数字环境充分发挥您周围丰富学习资源的价值&#xff0c;例如在线课程、网络研讨会、书籍、文章、论坛…

threejs(8)-详解光线投射与物体交互

详解光线投射与物体交互 import * as THREE from "three"; // 导入轨道控制器 import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"; // 导入动画库 import gsap from "gsap"; // 导入dat.gui import * as dat from &qu…