今天给大家讲一下基于JWT&RSA的单点登录(Single Sign On,简称SSO)解决方案

概念

首先要了解几个概念

  • 单点登录(Single Sign On)
  • JWT
  • RSA

背景

为什么需要单点登录?简单的来说就是http请求是无状态的,你的上一次请求和下一次请求都是没有关联的,那么怎么让服务器知道你是谁?他是谁?

会话机制

说到会话机制你肯定会想到session和cookie

  • session将会话id作为每一个请求的参数,服务器接收请求自然能解析参数获得会话id,判断是否来自同一会话。
  • cookie和session的作用一致,最大的区别就是session保存在浏览器,session保存在服务器

随着web系统的发展,现在的系统结构已经很复杂了,web系统早已从久远的单系统发展成为如今由多系统组成的应用群,面对如此众多的系统,用户难道要一个一个登录、然后一个一个注销吗?

因此,我们需要一种全新的登录方式来实现多系统应用群的登录,这就是单点登录

单点登录

单点登录说白了就是,把你的登录信息保存在token中,用户发起http请求时把token带上,服务器在接收到请求时去解析token,拿到你的登录信息,就知道你是谁了。

更多关于单点登录:传送门

JWT&RSA

JWT 和 RSA 可以说是单点登录是实现方式

JWT

JWT就是一个字符串也可以称为token,它把你的信息加密后生成一个字符串,前端保存这个字符串,在发起请求的时候就带上token,后端接收到token进行解析...

关于JWT:传送门

RSA

RSA是一个加密方式,是一种非对称的加密方式,为什么叫非对称加密方式?

因为它的加密和解密用的不是同一个密钥

加密使用公钥加密,解密用过私钥解密,私钥保存到后端,通过RSA就大大的提高了信息的安全性

关于密钥,私钥,公钥的区别:传送门

总结

使用JWT&RSA实现单点登录,通过RSA对公钥和私钥字符串进一步处理,JWT生成Token时,使用公钥进行加密,解析时,JWT通过私钥对Token进行解析(token可以设置过期时间,如果token过期,会自动解析失败)

代码

JwtUtils

package com.example.jwtras.utils;

import com.example.jwtras.entity.Employee;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.apache.commons.beanutils.BeanUtils;
import org.joda.time.DateTime; import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException; import java.security.PrivateKey;
import java.security.PublicKey; /**
* @author FENGZENG
* @date 2021/8/23 17:30
*/
public class JwtUtils { private static final String FORMAT_STR = "yyyy-MM-dd HH:mm:ss"; /**
* 生成token
*
* @param data 加密的数据
* @param expireMinutes token过期时间
* @param privateKey 私钥
* @return token
* @throws IntrospectionException
* @throws InvocationTargetException
* @throws IllegalAccessException
*/
public static String generateToken(Object data, int expireMinutes, PrivateKey privateKey) throws IntrospectionException, InvocationTargetException, IllegalAccessException {
JwtBuilder jwtBuilder = Jwts.builder();
if (data == null) {
throw new RuntimeException("数据不能为空");
}
//拿到bean信息
BeanInfo beanInfo = Introspector.getBeanInfo(Employee.class);
//获取bean的属性
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
//把bean的字符属性放入token中
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
//获取bean的属性名
String name = propertyDescriptor.getName();
//获取属性对应的value
Object value = propertyDescriptor.getReadMethod().invoke(data);
if (value != null) {
jwtBuilder.claim(name, value);
}
}
//设置token过期时间
jwtBuilder.setExpiration(DateTime.now().plusMinutes(expireMinutes).toDate());
//使用私钥进行加密
jwtBuilder.signWith(SignatureAlgorithm.RS256, privateKey);
//生成token
return jwtBuilder.compact();
} /**
* 解析token,获取token中存储的对象
* @param token token
* @param publicKey 公钥字符串
* @param beanClass beanClass
* @param <T> 泛型
* @return
*/
public static <T> T getObjectFromToken(String token, PublicKey publicKey, Class<T> beanClass) { try {
//获取token中存储的信息
Claims body = Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token).getBody();
//获取bean对象,实例化还为初始化
T bean = beanClass.newInstance();
//内省 Java bean 并了解其所有属性、公开的方法和事件
BeanInfo beanInfo = Introspector.getBeanInfo(beanClass); //获取bean的属性和value,类似Map结构
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
//拿到属性名
String name = propertyDescriptor.getName();
//拿到属性名对应的值
Object value = body.get(name);
if (value != null) {
//实例化bean
BeanUtils.setProperty(bean, name, value);
}
}
return bean;
} catch (Exception e) { //如果token过期,会自动解析失败
throw new RuntimeException("token已失效");
}
} }

RsaUtils

package com.example.jwtras.utils;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64; /**
* @author FENGZENG
* @date 2021/8/23 17:44
*/
public class RsaUtils { private static String algorithm = "RSA"; /**
* 获取 私钥对象
* @param key 私钥字符串
* @return
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
*/
public static PrivateKey getPrivateKey(String key) throws NoSuchAlgorithmException, InvalidKeySpecException {
//对key进行base64加密
byte[] decode = Base64.getDecoder().decode(key);
//使用PKCS8进行加密
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(decode);
//加密方式RSA
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
//生成privateKey
return keyFactory.generatePrivate(pkcs8EncodedKeySpec);
} /**
* 获取公钥对象
* @param key 公钥字符串
* @return
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
*/
public static PublicKey getPublicKey(String key) throws NoSuchAlgorithmException, InvalidKeySpecException {
// 对key进行base64加密
byte[] decode = Base64.getDecoder().decode(key);
//公钥使用X509进行加密
X509EncodedKeySpec spec = new X509EncodedKeySpec(decode);
//加密方式RSA
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
//生成publicKey
return keyFactory.generatePublic(spec);
} /**
* 从文件中读取密钥
* @param filename 传入文件名,相对于classpath
* @return
* @throws IOException
*/
private static byte[] readFile(String filename) throws IOException {
return Files.readAllBytes(new File(filename).toPath());
} }

tips

把个人信息放入到token中,使用的BeanInfoPropertyDescriptor其实是我学习别人的代码的时候碰到的,我还没有去细看,

另外一个方案就是序列化,可以直接把对象序列化成json串放到token中,拿到token时再反序列化得到序列化信息。

序列化可以使用Gson,fastJson,jackson

JWT&RSA实现单点登录(详细介绍)的更多相关文章

  1. Spring Security整合JWT,实现单点登录,So Easy~!

    前面整理过一篇 SpringBoot Security前后端分离,登录退出等返回json数据,也就是用Spring Security,基于SpringBoot2.1.4 RELEASE前后端分离的情况 ...

  2. 著名ERP厂商的SSO单点登录解决方案介绍一

          SSO英文全称Single Sign On,单点登录.SSO是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统.它包括可以将这次主要的登录映射到其他应用中用于同一个用户 ...

  3. 看图理解JWT如何用于单点登录

    单点登录是我比较喜欢的一个技术解决方案,一方面他能够提高产品使用的便利性,另一方面他分离了各个应用都需要的登录服务,对性能以及工作量都有好处.自从上次研究过JWT如何应用于会话管理,加之以前的项目中也 ...

  4. SSO之CAS单点登录详细搭建教程

    本教程是我个人编写,花费几个小时的时间,给需要学习的人员学习使用,希望能帮助到你们. [环境说明]:本文演示过程在同一个机器上的(也可以在三台实体机器或者三个的虚拟机上),环境如下: windows7 ...

  5. CAS单点登录详细流程

    一.CAS简介和整体流程 CAS 是 Yale 大学发起的一个开源项目,旨在为 Web 应用系统提供一种可靠的单点登录方法,CAS 在 2004 年 12 月正式成为 JA-SIG 的一个项目.CAS ...

  6. 基于JWT机制的单点登录

    使用JWT实现单点登录时,需要注意token时效性.token是保存在客户端的令牌数据,如果永久有效,则有被劫持的可能.token在设计的时候,可以考虑一次性有效或一段时间内有效.如果设置有效时长,则 ...

  7. CAS SSO单点登录框架介绍

    1.了解单点登录  SSO 主要特点是: SSO 应用之间使用 Web 协议(如 HTTPS) ,并且只有一个登录入口. SSO 的体系中有下面三种角色: 1) User(多个) 2) Web 应用( ...

  8. JWT 多网站单点登录,放弃session

    多个网站之间的登录信息共享, 基于cookie - session的登录认证方式跨域等比较复杂.采用基于算法的认证方式, JWT(json web token)的方式. --------------- ...

  9. 使用JWT来实现单点登录功能

    出处: https://www.cnblogs.com/zexin/p/10389541.html 我们平时自己开发项目,分布式的结构时,访问量不大,但是又不想搭建redis服务器,这时我觉得jwt不 ...

随机推荐

  1. Java数组(Array)和列表(ArryList)有什么区别?

    Array和ArryList的不同点 Array可以包含基本类型和对象类型,ArrayList只能包含对象类型 Array大小是固定的,ArrayList的大小动态变化的 ArrayList提供了更多 ...

  2. 痞子衡嵌入式:MCUBootUtility v3.5发布,支持串行NOR的ECC及双程序启动

    -- 痞子衡维护的 NXP-MCUBootUtility 工具距离上一个大版本(v3.4.0)发布过去半年了,这一次痞子衡为大家带来了版本升级 v3.5.0,这个版本主要有几个非常重要的更新需要跟大家 ...

  3. nf-Press —— 在线文档也可以加载组件和编写代码

    如果帮助文档可以加载组件,那么在介绍的同时就可以运行演示demo,是不是很酷? 如果可以在线修改运行代码,那么是不是更容易理解? 上一篇 https://www.cnblogs.com/jyk/p/1 ...

  4. CentOS停更;阿里发布全新操作系统(Anolis OS)

    镜像下载.域名解析.时间同步请点击阿里云开源镜像站 Linux系统对于Java程序员来说,就好比"乞丐手里的碗",任何业务都离不开他的身影,因为服务端的广泛使用,也因此衍生出了各种 ...

  5. 5月2日 python学习总结 IO模型

    IO模型 1.阻塞IO 2.非阻塞IO 3.多路复用IO 4.异步IO 一.阻塞IO blocking IO的特点就是在IO执行的两个阶段(等待数据和拷贝数据两个阶段)都被block了. 实际上,除非 ...

  6. javaweb项目中关于配置文件web.xml的解析

    一..启动tomcat,加载项目中的web.xml文件,创建servercontext上下文对象. 可以通过servercontext对象在应用中获取web.xml文件中的值. web应用加载的顺序与 ...

  7. 提升组件库通用能力 - NutUI 在线主题定制功能探索

    开发背景 NutUI 作为京东风格的组件库,已具备 H5 和多端小程序开发能力.随着业务的不断发展,组件库的应用场景越来越广.在公司内外面临诸如科技.金融.物流等各多个大型团队使用时,单一的京东 AP ...

  8. Kafka03--Kafka消费者使用方式

    前言 与生产者客户端一样,消费者端也由最初的scala版本过渡到现在的Java版本. 正常的消费者逻辑需要以下4个步骤: KafkaConsumer的客户端参数配置和对应实例: 订阅主题 拉取消息并消 ...

  9. Http请求的Get和Post的区别?

    1. get从地址栏以明文的方式提交请求信息内容?username=admin&password=123,用户可见, 而post从请求正文提交请求信息内容,用户不可见. 2. get提交因为是 ...

  10. 深入理解Java虚拟机-HotSpot虚拟机对象探秘

    一.对象的创建过程 虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载.解析和初始化过.如果没有,那就先执行相应的类 ...