基于公私密钥的单点登录

目前已知的单点登陆方式有:

多个系统集群

建立一个SSO认证中心,用户只需要登录一次就可以访问所有相互信任的应用系统。

1、可以通过session广播机制实现:在一个集群中的一个模块登录后,然后把这个session复制n份,发送到这个集群的其他模块中,就实现了一处登录,处处可用,但缺点是耗费比较大,不推荐使用

2、使用cookie+redis实现:在项目中任何一个模块登录,登录之后,把数据放到这两个地方

(1)redis:在key:生成唯一随机值(ip、用户id等等)  ,在value:用户数据

(2)cookie:把redis里面生成key值放到cookie里面

访问项目中其他模块,发送请求带着cookie进行发送,服务端获取请求中的cookie,把cookie获取值,到redis进行查询,根据key进行查询,如果查询数据就是登录

点对点系统

3、使用token实现

token:按照一定规则生成字符串,字符串可以包含用户信息的令牌

在项目某个模块进行登录,登录之后,按照规则生成字符串,把登陆之后用户包含到生成字符串里面,把字符串返回

(1)可以把字符串通过cookie返回

(2)把字符串通过地址栏返回

2.再去访问项目其他模块,每次访问在地址栏带着生成的字符串,在访问模块里面获取地址字符串,根据字符串获取用户信息。如果可以获取到,就是登录

基于公私密钥的单点登录

针对两个系统之间的单点登陆,使用token类似方式实现是最简单的。这里,我们通过一定的规则构造字符串(必须带有用户账户信息),并根据已有的私钥进行加密签名,返回到url中,请求目标系统,目标系统解析url中的签名,并根据公钥进行验签,通过之后,允许登陆,写入登陆信息到session。

公私秘钥的安全性由算法保证。算法是基于DSA签名, PKCS #8和X509是对应算法的处理类。对私钥按照 PKCS #8 标准编码处理、对公钥是使用了X509。 

DSA算法概述

DSA算法是美国的国家标准数字签名算法,它只能用户数字签名,而不能用户数据加密和密钥交换。

DSA与RSA的生成方式不同,RSA是使用openssl提供的指令一次性的生成密钥(包括公钥),而通常情况下,DSA是先生成DSA的密钥参数,然后根据密钥参数生成DSA密钥(包括公钥),密钥参数决定了DSA密钥的长度,而且一个密钥参数可以生成多对DSA密钥对。

DSA生成的密钥参数是p、q和g,如果要使用一个DSA密钥,需要首先共享其密钥参数。关于DSA加密的原理,请自行查阅。

私钥、公钥的获取可以使用OpenSSL工具生成,文章:https://www.jianshu.com/p/35ae4fb9e4a3

生成加密密钥部分参考

private static final String DSA = "DSA";
private static SimpleDateFormat CRED_TIME_FORMAT = new SimpleDateFormat("yyyyMMddHHmm");
private static String CRED_SEPERATOR = ":";
private static String signatureAlg = "SHA1WithDSA";
private static String SELF_PROJECTENAME = "A";
  
private static String privateKeyStr = "******";
private static String publicKeyStr = "*****"



KeyFactory keyFactory = KeyFactory.getInstance(DSA);
//对私钥解密
byte pri[] = ByteUtils.decodeHex(privateKeyStr);
 //取私钥
PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(pri);
PrivateKey priKey = keyFactory.generatePrivate(privKeySpec);Calendar now = Calendar.getInstance();
String minuteStr = CRED_TIME_FORMAT.format(now.getTime());
  
StringBuffer str = new StringBuffer();
//增加判定的其他参数
str.append(minuteStr).append(CRED_SEPERATOR).append(user).append(
CRED_SEPERATOR).append(self).append(CRED_SEPERATOR).append(
target);
//对数据签名
Signature sig = Signature.getInstance(signatureAlg);
sig.initSign(priKey);
sig.update(str.toString().getBytes("UTF8"));
byte[] signature = sig.sign();
  
String signatureStr = ByteUtils.encodeHex(signature);
str.append(CRED_SEPERATOR).append(signatureStr);

解析加密密钥部分参考

KeyFactory keyFactory = KeyFactory.getInstance(DSA);
//对公钥解密
//解析步骤:1 获取p_password参数,检查参数格式是否正确
//        2 将p_password拆解为两部分,最后一个:前一部分是signTarget单点信息摘要,后一部分是signatureTxt签名
//        3 设置算法signature参数,包括公钥,信息摘要和签名,调用验证,返回是否验证通过的结果ok
   String[] segments = cre.split(CRED_SEPERATOR);
        if (segments.length != 5) {
            logger.warn("票据应该是5段");
            return null;
        }
        //时间
        String ticketTime = segments[0];
        //登录用户名
        String ssoUser = segments[1];
        //源系统
        String srcSystem = segments[2];
        //目标系统
        String targetSystem = segments[3];
        //私钥签名
        String signatureTxt = segments[4];
 
 
String signTarget = cre.substring(0, cre.lastIndexOf(CRED_SEPERATOR));
 
 
 
byte pub[] = ByteUtils.decodeHex(publicKeyStr);
//取公钥
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(pub);
PublicKey pubKey = keyFactory.generatePublic(pubKeySpec);
  
byte[] signature = ByteUtils.decodeHex(signatureTxt);
Signature sig = Signature.getInstance(signatureAlg);
sig.initVerify(pubKey);
sig.update(signTarget.getBytes("UTF8"));
//验证签名
boolean ok = sig.verify(signature);

工具类ByteUtil

public class ByteUtils {
 
    /**
     * 转换md5码
     *
     * @param data 要转换的String
     * @return md5 md5码
     */
    public static final String MD5(String data) {
        try {
            MessageDigest digest = MessageDigest.getInstance("MD5");
            digest.update(data.getBytes("utf-8"));
            return encodeHex(digest.digest());
        } catch (Exception e) {
            throw new IllegalStateException(e.getMessage());
        }
    }
 
    /**
     * 将bytes字节转换成md5码
     *
     * @param bytes bytes
     * @return the string
     */
    public static final String encodeHex(byte bytes[]) {
        StringBuffer buf = new StringBuffer(bytes.length * 2);
        for (int i = 0; i < bytes.length; i++) {
            if ((bytes[i] & 0xff) < 16)
                buf.append("0");
            buf.append(Long.toString(bytes[i] & 0xff, 16));
        }
 
        return buf.toString();
    }
 
    /**
     * 字符串编码转为byte字节数组
     *
     * @param hex 要转换的字符串
     * @return byte[] 转换得到的byte编码
     */
    public static final byte[] decodeHex(String hex) {
        char chars[] = hex.toCharArray();
        byte bytes[] = new byte[chars.length / 2];
        int byteCount = 0;
        for (int i = 0; i < chars.length; i += 2) {
            int newByte = 0;
            newByte |= hexCharToByte(chars[i]);
            newByte <<= 4;
            newByte |= hexCharToByte(chars[i + 1]);
            bytes[byteCount] = (byte) newByte;
            byteCount++;
        }
 
        return bytes;
    }
 
    /**
     *
     */
    private static final byte hexCharToByte(char ch) {
        switch (ch) {
            case 48: // '0'
                return 0;
 
            case 49: // '1'
                return 1;
 
            case 50: // '2'
                return 2;
 
            case 51: // '3'
                return 3;
 
            case 52: // '4'
                return 4;
 
            case 53: // '5'
                return 5;
 
            case 54: // '6'
                return 6;
 
            case 55: // '7'
                return 7;
 
            case 56: // '8'
                return 8;
 
            case 57: // '9'
                return 9;
 
            case 97: // 'a'
                return 10;
 
            case 98: // 'b'
                return 11;
 
            case 99: // 'c'
                return 12;
 
            case 100: // 'd'
                return 13;
 
            case 101: // 'e'
                return 14;
 
            case 102: // 'f'
                return 15;
 
            case 58: // ':'
            case 59: // ';'
            case 60: // '<'
            case 61: // '='
            case 62: // '>'
            case 63: // '?'
            case 64: // '@'
            case 65: // 'A'
            case 66: // 'B'
            case 67: // 'C'
            case 68: // 'D'
            case 69: // 'E'
            case 70: // 'F'
            case 71: // 'G'
            case 72: // 'H'
            case 73: // 'I'
            case 74: // 'J'
            case 75: // 'K'
            case 76: // 'L'
            case 77: // 'M'
            case 78: // 'N'
            case 79: // 'O'
            case 80: // 'P'
            case 81: // 'Q'
            case 82: // 'R'
            case 83: // 'S'
            case 84: // 'T'
            case 85: // 'U'
            case 86: // 'V'
            case 87: // 'W'
            case 88: // 'X'
            case 89: // 'Y'
            case 90: // 'Z'
            case 91: // '['
            case 92: // '\\'
            case 93: // ']'
            case 94: // '^'
            case 95: // '_'
            case 96: // '`'
            default:
                return 0;
        }
    }
  

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JUC-01 线程的创建和状态转换

本次我们主要讲三个问题 线程是什么&#xff1f;线程有哪些状态&#xff1f;各状态间的转换了解吗&#xff1f;创建线程的3种方法你都了解吗&#xff1f; 1. 线程是什么&#xff1f;&#xff08;了解即可&#xff09; 进程&#xff1a; 进程是一个具有一定独立功能的程序在一…

计算机网络考试复习——第一章 1.7

1.7 计算机网络体系结构 两台计算机要互相传送文件需解决很多问题: (1) 必须有一条传送数据的通路。 (2) 发起方必须激活通路。 (3) 要告诉网络如何识别接收方。 (4) 发起方要清楚对方是否已开机&#xff0c;且与网络连接正常。 (5) 发起方要清楚对方是否准备好接收和存储文件…

数据结构——栈与队列相关题目

数据结构——栈与队列相关题目232. 用栈实现队列思路225. 用队列实现栈1.两个队列实现栈2.一个队列实现栈20. 有效的括号思路1047. 删除字符串中的所有相邻重复项思路155. 最小栈150. 逆波兰表达式求值思路239. 滑动窗口最大值单调队列347. 前 K 个高频元素思路232. 用栈实现队…

2023版Postman接口测试使用全指南(原来使用 Postman测试API接口如此简单)

下面是一篇详细介绍postman接口测试的文章&#xff0c;如果文章内容不太明白的话&#xff0c; 我建议看看视频版本&#xff0c;更加清洗&#xff0c;更加直观&#xff01; 最详细的postman接口测试实战教程_哔哩哔哩_bilibili最详细的postman接口测试实战教程共计129条视频&am…

ToBeWritten之ARM汇编基础铺垫

也许每个人出生的时候都以为这世界都是为他一个人而存在的&#xff0c;当他发现自己错的时候&#xff0c;他便开始长大 少走了弯路&#xff0c;也就错过了风景&#xff0c;无论如何&#xff0c;感谢经历 转移发布平台通知&#xff1a;将不再在CSDN博客发布新文章&#xff0c;敬…

FPGA解码4line MIPI视频 IMX291/IMX290摄像头采集 提供工程源码和技术支持

目录1、前言2、Xilinx官方主推的MIPI解码方案3、我已有的MIPI解码方案4、纯Vhdl代码解码MIPI5、vivado工程介绍6、上板调试验证7、福利&#xff1a;工程代码的获取1、前言 FPGA图像采集领域目前协议最复杂、技术难度最高的应该就是MIPI协议了&#xff0c;MIPI解码难度之高&…

关键词采集软件在SEO优化中的应用与效果

搜索引擎的优化被广泛认为是提高网站排名和在线可见性的重要方法之一。SEO人员需要进行大量的工作以确保网站的内容和标签可以被搜索引擎正确地解析和索引。在这项任务中&#xff0c;使用搜索引擎关键词采集软件可以帮助SEO人员完成许多繁琐的任务并简化他们的工作流程。在本文…

Linux 基础IO(Input与output)学习

进程间通信&#xff1a;讲的是操作系统为用户提供的几种进程间的通信方式概念&#xff1a;进程间通信其实就是多个进程之间进行数据交互问题&#xff1a;进程间通信为什么不能直接进行数据交互&#xff0c;需要使用系统提供的方式&#xff1f;原因&#xff1a;进程之间是具有独…

电动力学问题中的Matlab可视化

电磁场的经典描述 小说一则 电磁场的经典描述就是没有啥玩意量子力学的经典电动力学下对电磁场的描述,以后有空写个科幻小说,写啥呢,就写有天张三遇见了一个外星人,外星人来自这样一个星球,星球上的物质密度特别低,导致外星人的测量会明显的影响物质的运动,外星人不能同时得到…

JNI 调用

简介 JNI是Java Native Interface的缩写&#xff0c;通过使用 Java本地接口书写程序&#xff0c;可以确保代码在不同的平台上方便移植。从Java1.1开始&#xff0c;JNI标准成为java平台的一部分&#xff0c;它允许Java代码和其他语言写的代码进行交互。 本地代码与 Java 虚拟机…

【ChatGPT】ChatGPT-5 强到什么地步?

Yan-英杰的主页 悟已往之不谏 知来者之可追 C程序员&#xff0c;2024届电子信息研究生 目录 ChatGPT-5 强到什么地步&#xff1f; 技术 深度学习模型的升级 更好的预测能力 自适应学习能力 特点 语言理解能力更强 自我修正和优化 更广泛的应用领域 应用 对话系统 智能写作…

【机器学习】吴恩达机器学习Deeplearning.ai

机器学习已经强大到可以独立成为人工智能的一个子领域。 可以通过对机器编程实现比如执行网络搜索、理解人类语言、通过x光诊断疾病&#xff0c;或制造自动驾驶汽车。 机器学习定义 一般来说&#xff0c;给一个算法学习的机会越多&#xff0c;它的表现就越好。 机器学习的两种…

阿里云5、6代云服务器实例免费升级至第7代(不限次数)

简介&#xff1a; 阿里云推出云服务器实例免费升级至第7代优惠活动&#xff0c;第5、&#xff16;代云服务器&#xff0c;可享受实例部分免费升级至第7代实例&#xff0c;让你的云服务器拥有更高的安全、存储、网络等性能。 阿里云服务器升级有优惠吗&#xff1f;当然是有的&am…

长安信托:拥抱数字信托,探索多项目管理新路径

长安信托&#xff1a;公司使用 ONES 已经 2 年了。ONES 最大的优势是能够有效串联我司信息科技研发过程中的各个环节&#xff0c;从需求管理到研发任务跟踪&#xff0c;再到测试管理&#xff0c;ONES 能明确地展示出业务部门从需求提出到研发上线的全链路&#xff0c;体现信息科…

免费ChatGPT接入-国内怎么玩chatGPT

免费ChatGPT中文版 OpenAI 的 GPT 模型目前并不提供中文版的免费使用&#xff0c;但是有许多机器学习平台和第三方服务提供商也提供了基于 GPT 技术的中文版模型和 API。下面是一些常见的免费中文版 ChatGPT&#xff1a; Hugging Face&#xff1a;Hugging Face 是一个开源社区…

后缀为whl的文件是什么?如何安装whl文件?学习一下(22)

小朋友们好&#xff0c;大朋友们好&#xff01; 我是猫妹&#xff0c;一名爱上Python编程的小学生。 欢迎和猫妹一起&#xff0c;趣味学Python。 今日主题 了解并使用Pyhton的库安装包文件whl。 什么是whl文件 whl格式本质上是一个压缩包&#xff0c;里面包含了py文件&am…

chatGPA的主要功能-chatGPT深度分析

ChatGPT功能介绍 ChatGPT是基于深度学习技术的自然语言处理算法&#xff0c;其主要用途是生成自然语言文本&#xff0c;能够应用于多个自然语言处理任务。以下是其主要功能介绍&#xff1a; 文本生成&#xff1a;ChatGPT能够生成高质量的自然语言文本&#xff0c;可以应用于大…

linux常用系统管理经验谈

Lab1 硬件和安装 步骤一&#xff1a;准备计算机 任务&#xff1a; 使用Red Hat Linux光盘启动系统 在启动时进入BIOS界面 设置系统启动顺序为A&#xff0c;CDROM&#xff0c;C 修改其他任何推荐的设置 保存并退出BIOS设置 步骤二&#xff1a;使用Anaconda&#xff08;图形模式…

二十分钟带你了解JVM性能调优与实战进阶

ZGC 诞生原因 Java生态非常强大&#xff0c;但还不够&#xff0c;有些场景仍处于劣势&#xff0c;而ZGC的出现可以让Java语言抢占其他语言的某些特定领域市场。比如 谷歌主导的Android手机系统显示卡顿。证券交易市场&#xff0c;实时性要求非常高&#xff0c;目前主要是C主…

阿里云版GPT官宣,我们问了它10个问题

4月7日&#xff0c;阿里云宣布自研大模型“通义千问”&#xff0c;目前已开始邀请用户测试体验。 阿里达摩院在NLP自然语言处理等前沿科研领域早已布局多年&#xff0c;并于2019年启动大模型研发&#xff0c;通义千问便是其最新成果&#xff0c;相当于阿里云版的“ChatGPT”。 …