SpringBoot+JWT实现单点登录解决方案

一、什么是单点登录?

单点登录是一种统一认证和授权机制,指在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的系统,不需要重新登录验证。

单点登录一般用于互相授信的系统,实现单一位置登录,其他信任的应用直接免登录的方式,在多个应用系统中,只需要登录一次,就可以访问其他互相信任的应用系统。

随着时代的演进,大型web系统早已从单体应用架构发展为如今的多系统分布式应用群。但无论系统内部多么复杂,对用户而言,都是一个统一的整体,访问web系统的整个应用群要和访问单个系统一样,登录/注销只要一次就够了,不可能让一个用户在每个业务系统上都进行一次登录验证操作,这时就需要独立出一个单独的认证系统,它就是单点登录系统。

二、单点登录的优点

1.方便用户使用。用户不需要多次登录系统,不需要记住多个密码,方便用户操作。

2.提高开发效率。单点登录为开发人员提供类一个通用的验证框架。

3.简化管理。如果在应用程序中加入了单点登录的协议,管理用户账户的负担就会减轻。

三、JWT 机制

JWT(JSON Web Token)它将用户信息加密到token里,服务器不保存任何用户信息。服务器通过使用保存的密钥验证JWTToken的正确性,只要正确就通过验证。

数据结构:

JWT包含三个部分:Header头部,Payload负载和Signature签名。三个部门用“.”分割。校验也是JWT内部自己实现的 ,并且可以将你存储时候的信息从token中取出来无须查库。

JWT执行流程:

JWT的请求流程也特别简单,首先使用账号登录获取Token,然后后面的各种请求,都带上这个Token即可。具体流程如下:

1. 客户端发起登录请求,传入账号密码;

2. 服务端使用私钥创建一个Token;

3. 服务器返回Token给客户端;

4. 客户端向服务端发送请求,在请求头中携带Token;

5. 服务器验证该Token;

6. 返回结果。

四.创建Maven父项目

 2.指定打包类型为pom

 五.创建认证模块sso

 1.添加依赖,完整的pom文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.13</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.example</groupId><artifactId>sso</artifactId><version>0.0.1-SNAPSHOT</version><name>sso</name><description>sso</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!--jwt--><dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.8.2</version></dependency><!--thymeleaf--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

2添加jwt相关配置

 

 

 3.创建JWT配置类和JWT工具类

示例代码如下:

package com.example.sso.bean;import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;/*** @author qx* @date 2023/7/4* @des Jwt配置类*/
@Component
@ConfigurationProperties(prefix = "jwt")
@Getter
@Setter
public class JwtProperties {/*** 过期时间-分钟*/private Integer expireTime;/*** 密钥*/private String secret;
}
package com.example.sso.util;import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.example.sso.bean.JwtProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.util.Date;/*** @author qx* @date 2023/7/4* @des JWT工具类*/
@Component
public class JwtUtil {@Autowiredprivate JwtProperties jwtProperties;/*** 生成一个jwt字符串** @param username 用户名* @return jwt字符串*/public String sign(String username) {Algorithm algorithm = Algorithm.HMAC256(jwtProperties.getSecret());return JWT.create()// 设置过期时间1个小时.withExpiresAt(new Date(System.currentTimeMillis() + jwtProperties.getExpireTime() * 60 * 1000))// 设置负载.withClaim("username", username).sign(algorithm);}public static void main(String[] args) {Algorithm algorithm = Algorithm.HMAC256("KU5TjMO6zmh03bU3");String username = "admin";String token = JWT.create()// 设置过期时间1个小时.withExpiresAt(new Date(System.currentTimeMillis() + 60 * 60 * 1000))// 设置负载.withClaim("username", username).sign(algorithm);System.out.println(token);}/*** 校验token是否正确** @param token token值*/public boolean verify(String token) {if (token == null || token.length() == 0) {throw new RuntimeException("token为空");}try {Algorithm algorithm = Algorithm.HMAC256(jwtProperties.getSecret());JWTVerifier jwtVerifier = JWT.require(algorithm).build();jwtVerifier.verify(token);return true;} catch (Exception e) {e.printStackTrace();return false;}}}

4.创建服务层

package com.example.sso.service;import com.example.sso.util.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;/*** @author qx* @date 2023/7/4* @des 登录服务层*/
@Service
public class LoginService {@Autowiredprivate JwtUtil jwtUtil;/*** 登录** @param username 用户名* @param password 密码* @return token值*/public String login(String username, String password) {if ("".equals(username) || "".equals(password)) {throw new RuntimeException("用户名或密码不能为空");}// 为了测试方便 不去数据库比较密码if ("123".equals(password)) {// 返回生成的tokenreturn jwtUtil.sign(username);}return null;}/*** 校验jwt是否成功** @param token    token值* @return 校验是否超过*/public boolean checkJwt(String token) {return jwtUtil.verify(token);}
}

5.创建控制层

package com.example.sso.controller;import com.example.sso.service.LoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;/*** @author qx* @date 2023/7/4* @des 验证控制层*/
@Controller
@RequestMapping("/sso")
public class AuthController {@Autowiredprivate LoginService loginService;/*** 登录页面*/@GetMapping("/login")public String toLogin() {return "login";}/*** 登录** @param username 用户名* @param password 密码* @return token值*/@PostMapping("/login")@ResponseBodypublic String login(String username, String password) {return loginService.login(username, password);}/*** 验证jwt** @param token token* @return 验证jwt是否合法*/@RequestMapping("/checkJwt")@ResponseBodypublic boolean checkJwt(String token) {return loginService.checkJwt(token);}}

6.创建一个登录页面login.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>登录</title>
</head>
<body><form method="post" action="/sso/login">用户名:<input type="text" name="username"/><br/>密码:<input type="password" name="password"/><br/><button type="submit">登录</button></form>
</body>
</html>

六、创建应用系统projectA 

 1.项目pom文件如下所示

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.example</groupId><artifactId>my-sso</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>projectA</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2.7.13</version></dependency><!--okhttp--><dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp</artifactId><version>4.10.0</version></dependency></dependencies>
</project>

 2.修改配置文件

 

 3.创建过滤器

package com.example.projectA.filter;import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;/*** @author qx* @date 2023/7/4* @des 登录过滤器*/
@Component
@WebFilter(urlPatterns = "/**")
public class LoginFilter implements Filter {@Value("${sso_server}")private String serverHost;@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;String token = httpServletRequest.getParameter("token");if (this.check(token)) {filterChain.doFilter(servletRequest, servletResponse);} else {HttpServletResponse response = (HttpServletResponse) servletResponse;String redirect = serverHost + "/login";response.sendRedirect(redirect);}}/*** 验证token** @param token* @return* @throws IOException*/private boolean check(String token) throws IOException {if (token == null || token.trim().length() == 0) {return false;}OkHttpClient client = new OkHttpClient();// 请求验证token的合法性String url = serverHost + "/checkJwt?token=" + token;Request request = new Request.Builder().url(url).build();Response response = client.newCall(request).execute();return Boolean.parseBoolean(response.body().string());}
}

4.创建测试控制层

package com.example.projectA.controller;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;/*** @author qx* @date 2023/7/4* @des 测试A*/
@RestController
public class IndexController {@GetMapping("/testA")public String testA() {return "输出testA";}
}

5.启动类

package com.example.projectA;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;/*** @author qx* @date 2023/7/4* @des Projecta启动类*/
@SpringBootApplication
@ServletComponentScan
public class ProjectaApplication {public static void main(String[] args) {SpringApplication.run(ProjectaApplication.class,args);}
}

6.启动项目测试

我们访问http://localhost:8081/testA 系统跳转到了验证模块的登录页面

我们输入账号密码登录成功后返回token

 

 如何我们复制这段数据,把数据传递到token参数。

 我们看到正确获取到了数据。

七、创建应用系统projectB

我们再次模仿projectA创建projectB子模块。

 

 

 启动模块B

我们直接测试带上token参数

 

通过之前的token,无需登录即可成功进入了应用系统B。说明我们的单点登录系统搭建成功。

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

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

相关文章

机器学习技术(五)——特征工程与模型评估

机器学习技术&#xff08;五&#xff09;——特征工程与模型评估(2️⃣) 文章目录 机器学习技术&#xff08;五&#xff09;——特征工程与模型评估(:two:)二、模型评估1、Accuracy score2、Confusion matrix混淆矩阵1、多值2、二值 3、Hamming loss4、Precision, recall and F…

深度学习笔记之Transformer(八)Transformer模型架构基本介绍

机器学习笔记之Transformer——Transformer模型架构基本介绍 引言回顾&#xff1a;简单理解&#xff1a; Seq2seq \text{Seq2seq} Seq2seq模型架构与自编码器自注意力机制 Transformer \text{Transformer} Transformer架构关于架构的简单认识多头注意力机制包含掩码的多头注意力…

Elasticsearch【全文检索、倒排索引、应用场景、对比Solr、数据结构】(一)-全面详解(学习总结---从入门到深化)

目录 Elasticsearch介绍_全文检索 Elasticsearch介绍_倒排索引 Elasticsearch介绍_Elasticsearch的出现 Elasticsearch介绍_Elasticsearch应用场景 Elasticsearch介绍_Elasticsearch对比Solr Elasticsearch介绍_Elasticsearch数据结构 Elasticsearch介绍_全文检索 Elasti…

libvirt 热迁移流程及参数介绍

01 热迁移基本原理 1.1 热迁移概念 热迁移也叫在线迁移&#xff0c;是指虚拟机在开机状态下&#xff0c;且不影响虚拟机内部业务正常运行的情况下&#xff0c;从一台宿主机迁移到另外一台宿主机上的过程。 1.2 虚拟机数据传输预拷贝和后拷贝 预拷贝(pre-copy)&#xff1a; …

Windows如何恢复已删除的Word文档?

案例&#xff1a;可以恢复已删除的Word文档吗&#xff1f; “大家好&#xff0c;我遇到了一个问题&#xff0c;需要大家的帮助。昨天我编辑了一个Word文档并保存到了桌面上&#xff0c;但当我今天再次打开电脑时&#xff0c;它就不见了&#xff01;昨天工作完成后&#xff…

Sentinel 规则详解

Sentinel 规则 流控规则 flow1、QPS流控2、并发线程数流控3、流控模式4、流控效果 熔断&#xff08;降级&#xff09;规则 degrade1、慢调用比例2、异常比例3、异常数 热点规则 param-flow授权规则 authority1、应用场景2、自定义来源3、授权规则配置 系统规则 前言&#xff1a…

JMeter进行WebSocket压力测试

背景 之前两篇内容介绍了一下 WebSocket 和 SocketIO 的基础内容。之后用 Netty-SocketIO 开发了一个简单的服务端&#xff0c;支持服务端主动向客户端发送消息&#xff0c;同时也支持客户端请求&#xff0c;服务端响应方式。本文主要想了解一下服务端的性能怎么样&#xff0c;…

4.6.tensorRT基础(1)-实际模型上onnx文件的各种操作

目录 前言1. onnx1.1 读取节点1.2 修改节点1.3 替换节点1.4 删除节点1.5 修改input和output1.6 预处理的接入 总结 前言 杜老师推出的 tensorRT从零起步高性能部署 课程&#xff0c;之前有看过一遍&#xff0c;但是没有做笔记&#xff0c;很多东西也忘了。这次重新撸一遍&#…

【深度学习】神经网络初学者指南

一、说明 这是一篇对神经网络的泛泛而谈的文章&#xff0c;我的意见是&#xff0c;先知道框架&#xff0c;而后知道每一个细节&#xff0c;这是学习人工智能的基本路线。本文就神经网络而言&#xff0c;谈到一些基础概念&#xff0c;适应于初学者建立概念。 二、神经网络定义 神…

计算机网络————网络层

文章目录 网络层设计思路IP地址IP地址分类IP地址与硬件地址 协议ARP和RARPIP划分子网和构造超网划分子网构造超网&#xff08;无分类编址CIDR&#xff09; ICMP 虚拟专用网VPN和网络地址转换NATVPNNAT 网络层设计思路 网络层向上只提供简单灵活的、无连接的、尽最大努力交付的数…

【MQTT】Esp32数据上传采集:最新mqtt插件(支持掉线、真机调试错误等问题)

前言 这是我在Dcloud发布的插件-最完整Mqtt示例代码&#xff08;解决掉线、真机调试错误等问题&#xff09;&#xff0c;经过整改优化和替换Mqtt的js文件使一些市场上出现的问题得以解决&#xff0c;至于跨端出问题&#xff0c;可能原因有很多&#xff0c;例如&#xff0c;合法…

<数据结构>并查集

目录 并查集概念 合并 查找集合的数量 并查集类代码实现 并查集概念 并查集和堆一样&#xff0c;都是通过数组来实现树的节点映射&#xff0c;不过并查集作用是&#xff0c;把一堆数据分为不同的几个小集合 不过并查集是森林的概念&#xff0c;并查集的学习可以帮助我们去更…

IDEA中侧边栏没有git commit模块,如何恢复?

一、修改之前 侧边栏没有git commit模块 二、修改之后 侧边栏恢复了git commit模块 三、下面是恢复教程 1.中文版 打开 文件 -> 设置 -> 版本控制 -> 提交 -> 勾选 【使用非模式提交界面】 -> 点击【确定】 2.英文版 打开 file -> Settings -> Version Co…

同步和异步的区别

同步&#xff0c;可以理解为在执行完一个函数或方法之后&#xff0c;一直等待系统返回值或消息&#xff0c;这时程序是处于阻塞的&#xff0c;只有接收到返回的值或消息后才往下执行其他的命令&#xff1b; 异步&#xff0c;执行完函数或方法后&#xff0c;不必阻塞性地等待返回…

Linux与Windows:操作系统的比较与技巧分享

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

【数学建模】国赛真题分析 2012 A题 葡萄酒的评价

2012 A题 葡萄酒的评价 优秀论文地址&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/19WGpybgM6RncxTYhx61JRA?pwdvl22 提取码&#xff1a;vl22 –来自百度网盘超级会员V6的分享 确定葡萄酒质量时一般是通过聘请一批有资质的评酒员进行品评。每个评酒员在对葡萄酒进…

计讯物联网关型水利遥测终端机TY910确保闸站自动化监测长效运行

闸站是我国水利建设工程的重要组成部分&#xff0c;具备调度水源、防洪排涝、灌溉等能力&#xff0c;在农业、水路运输、养殖业等行业领域起着关键作用&#xff0c;进而解决区域水资源不均衡的问题&#xff0c;促进水资源多方面的利用。当前&#xff0c;我国闸站存在数量多、分…

线性代数 4 every one(线性代数学习资源分享)

Linear Algebra 4 Every One 版权说明&#xff0c;以下我分享的都是一个名叫Kenji Hiranabe的日本学者&#xff0c;在github上分享的&#xff0c;关于Gilbert Strang教授所撰写的《Linear Algebra for Everyone》一书的总结&#xff0c;更像是一个非常精美的线性代数手册&#…

.net core 2.1 简单部署IIS运行

netcore的项目不像netFramework那么方便部署到iis还是要费点功夫的 比如我想把这个netcore2.1的项目部署到iis并运行&#xff1a; 按照步骤走&#xff1a; 一、确认自己的netcore环境 1、需要安装下面3个环境包(如果电脑已安装请忽略) 检查是否安装cmd命令&#xff1a;cmd&…

go mod vendor简明介绍

Go 语言在 go 1.6 版本以后编译 go 代码会优先从 vendor 目录先寻找依赖包&#xff0c;它具有以下优点&#xff1a; 复制依赖&#xff1a;go mod vendor 会把程序所依赖的所有包复制到项目目录下的vendor 文件夹中&#xff0c;所以即使这些依赖包在外部源&#xff08;如 GitHu…