SpringBoot Security OAuth2实现单点登录SSO(附源码)

news2024/11/15 1:54:30

在这里插入图片描述

文章目录

  • 基础概念
    • 1. 用户认证
    • 2. 单点登录(SSO)
    • 3. 授权管理
    • 4. 安全性和配置
  • 逻辑实现
    • 配置认证服务器
    • 配置Spring Security
    • 两个客户端
  • 页面展示
  • 本篇小结

更多相关内容可查看

附源码地址:https://gitee.com/its-a-little-bad/SSO.git

基础概念

Spring Boot Security 和 OAuth2 结合实现单点登录(SSO)功能主要涉及以下几个方面:

1. 用户认证

OAuth2 允许用户使用第三方认证提供者(如Google、GitHub等)的凭据进行认证,而不需要在你的应用中存储用户的密码。Spring Security 的 oauth2Login() 配置确保了在用户进行 OAuth2 认证后,他们将被重定向回你的应用程序并得到授权。
具体实现了:

  • 用户点击登录按钮,选择使用 Google、GitHub 等作为认证提供者。
  • 应用程序重定向用户到选择的认证提供者的登录页面。
  • 用户在认证提供者的页面上输入凭据(用户名密码或其他认证方式)进行身份验证。
  • 认证成功后,认证提供者重定向用户回到你的应用程序,并且带有授权码。
  • 应用程序使用授权码交换令牌,并获取用户信息,从而进行用户认证。

2. 单点登录(SSO)

如果在你的应用程序中配置了多个 OAuth2 客户端(例如同时配置了 Google 和 GitHub),用户在其中一个认证成功后,在访问其他配置的客户端时不需要重新认证。这是 OAuth2 的一个核心优势之一,实现了单点登录(SSO)功能。
具体实现了:

  • 用户首次使用某个 OAuth2 客户端进行登录认证后,应用程序会创建一个本地的用户会话。
  • 当用户访问其他受保护的端点时,应用程序会检查用户的会话状态并自动完成认证流程,而无需用户再次提供凭据。

3. 授权管理

OAuth2 除了用于认证外,还提供了授权机制。通过配置 scope,你可以限制第三方应用程序可以访问的用户信息范围。在实现中,你可以根据具体需求设置不同的 scope,来控制第三方应用程序的访问权限。
具体实现了:

  • 在 OAuth2 客户端配置中,通过设置 scope 来限制第三方应用程序可以请求的用户信息。

  • 应用程序根据 OAuth2 提供者返回的用户信息,对用户的权限和访问进行管理和控制。

4. 安全性和配置

Spring Security 提供了强大的安全特性,例如 CSRF 保护、会话管理、角色授权等。通过合理配置,你可以确保你的应用程序在实现单点登录功能的同时,也保持了高级别的安全性。
具体实现了:

  • 在 SecurityConfig 中配置了安全规则,确保只有经过认证的用户才能访问受保护的端点。
  • 根据需要配置会话管理策略,例如限制用户同时登录的设备数量或时间。

网上摘的图,便于理解

个人理解:通俗点来说最好的例子就是微信在登陆别的app或者小程序可以进行微信授权类似的意思然后那个小程序你就无需在进行输入账号密码了

在这里插入图片描述

逻辑实现

配置认证服务器

注:你可以把他理解为上述所说的微信

1.依赖:所有依赖可以拉取git拉取

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-oauth2-jose</artifactId>
</dependency>

2.application.yml配置 —需要配置自己的数据库信息,redis信息

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/permission?serverTimezone=UTC
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    show-sql: true
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQL5Dialect
  session:
    store-type: redis
  redis:
    host: 127.0.0.1
    port: 6379

server:
  port: 8080

3.配置OAuth2认证服务器–AuthorizationServerConfig文件

package com.cjs.sso.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.security.core.token.DefaultToken;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;

import javax.sql.DataSource;

/**
 * @author twl
 * @date
 */
@Configuration  // 声明这是一个配置类
@EnableAuthorizationServer  // 开启授权服务器功能
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired  // 自动注入数据源
    private DataSource dataSource;

    @Override  // 配置授权服务器的安全性,允许表单认证
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.allowFormAuthenticationForClients();
        security.tokenKeyAccess("isAuthenticated()");
    }

    @Override  // 配置客户端详情服务,客户端的信息将通过数据库来进行存储
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.jdbc(dataSource);
    }

    @Override  // 配置授权服务器端点的配置器,主要是一些非安全相关的配置,比如token存储、token自定义、授权模式等
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.accessTokenConverter(jwtAccessTokenConverter());
        endpoints.tokenStore(jwtTokenStore());
//        endpoints.tokenServices(defaultTokenServices());
    }

    /*@Primary  // 设置为主要的,优先使用的
    @Bean  // 声明一个Bean
    public DefaultTokenServices defaultTokenServices() {  // 默认的token服务
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(jwtTokenStore());
        defaultTokenServices.setSupportRefreshToken(true);
        return defaultTokenServices;
    }*/

    @Bean  // 声明一个Bean
    public JwtTokenStore jwtTokenStore() {  // JWT的token存储对象
        return new JwtTokenStore(jwtAccessTokenConverter());
    }

    @Bean  // 声明一个Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {  // JWT的token转换器
        JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
        jwtAccessTokenConverter.setSigningKey("cjs");   //  设置JWT签名密钥
        return jwtAccessTokenConverter;
    }

}

配置Spring Security

package com.cjs.sso.config;

import com.cjs.sso.service.MyUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * @author twl
 * @date 
 */
@Configuration  // 声明这是一个配置类
@EnableWebSecurity  // 开启Web安全功能
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired  // 自动注入用户详情服务
    private MyUserDetailsService userDetailsService;

    @Override  // 配置身份验证管理器
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    @Override  // 配置Web安全,忽略对于静态资源的安全控制
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/assets/**", "/css/**", "/images/**");
    }

    @Override  // 配置Http安全,包括登录页面、登录请求路径、其他请求的安全控制等
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()
                .loginPage("/login")  // 设置登录页面的路径
                .and()
                .authorizeRequests()
                .antMatchers("/login").permitAll()  // 对登录页面的请求不进行安全控制
                .anyRequest()
                .authenticated()  // 对其他所有请求都进行安全控制,必须通过身份验证
                .and().csrf().disable().cors();  // 禁用CSRF保护,启用跨域资源共享
    }

    @Bean  // 声明一个Bean
    public PasswordEncoder passwordEncoder() {  // 密码编码器,用于对密码进行编码
        return new BCryptPasswordEncoder();
    }

}

两个客户端

注:可以理解为两个微信小程序,可以通过微信进行授权登陆

1.application.yml配置

server:
  port: 8082
  servlet:
    context-path: /memberSystem
security:
  oauth2:
    client:
      client-id: UserManagement
      client-secret: user123
      access-token-uri: http://localhost:8080/oauth/token
      user-authorization-uri: http://localhost:8080/oauth/authorize
    resource:
      jwt:
        key-uri: http://localhost:8080/oauth/token_key
server:
  port: 8083
  servlet:
    context-path: /orderSystem
security:
  oauth2:
    client:
      client-id: OrderManagement
      client-secret: order123
      access-token-uri: http://localhost:8080/oauth/token
      user-authorization-uri: http://localhost:8080/oauth/authorize
    resource:
      jwt:
        key-uri: http://localhost:8080/oauth/token_key

2.添加依赖

        <dependency>
            <groupId>org.springframework.security.oauth.boot</groupId>
            <artifactId>spring-security-oauth2-autoconfigure</artifactId>
            <version>2.1.3.RELEASE</version>
        </dependency>

3.配置安全策略–WebSecurityConfig文件

创建并配置Spring Security以确保所有请求都经过Token验证:

package com.cjs.example.config;

import com.cjs.example.util.EnvironmentUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;


/**
 * @author twl
 * @date 
 */
@EnableOAuth2Sso
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private EnvironmentUtils environmentUtils;

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/bootstrap/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        if ("local".equals(environmentUtils.getActiveProfile())) {
            http.authorizeRequests().anyRequest().permitAll();
        }else {
            http.logout().logoutSuccessUrl("http://localhost:8080/logout")
                    .and()
                    .authorizeRequests()
                    .anyRequest().authenticated()
                    .and()
                    .csrf().disable();
        }
    }
}
package com.cjs.example.config;

import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

/**
 * @author twl
 * @date
 */
@EnableOAuth2Sso
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.logout().logoutSuccessUrl("http://localhost:8080/logout");
        http.authorizeRequests().anyRequest().authenticated();
        http.csrf().disable();
    }
}

页面展示

进入http://localhost:8080/登陆页面–点击登陆进行授权

在这里插入图片描述

授权完登陆跳转页面

在这里插入图片描述

直接访问http://localhost:8082/memberSystem/member/list

在这里插入图片描述

本篇小结

如果直接访问http://localhost:8082/memberSystem/member/list 也会自动跳转到http://localhost:8080/登陆界面,进行上述整篇都在说的认证服务器,但如果先登录认证服务器,在进行登陆8082端口这个服务,会直接进入8082页面,这就是所谓的已经授权过的无需在重复登陆的实现

这样描述大家应该都比较好理解了,这个无需自己敲其实,知道怎么实现的,面试能聊个大概即可,毕竟工作中很少会去做这个事情

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

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

相关文章

HarmonyOS 状态管理(一)

1. HarmonyOS 状态管理 1.1. 说明 官方文档&#xff08;https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/arkts-state-management-V5&#xff09; 1.1.1. 状态管理&#xff08;V1稳定版&#xff09; 状态管理&#xff08;V1稳定版&#xff09;提供了多种…

90+ Python 面试问答(2024 版)

90+ Python 面试问答(2024 版) 一、介绍 欢迎来到准备数据科学工作面试的第一步。这里有一个全面而广泛的 Python 面试问题和答案列表,可帮助您在面试中取得好成绩并获得理想的工作!Python 是一种解释型通用编程语言,由于其在人工智能 (AI) 中的使用,如今需求量很大。…

python大小写转换、驼峰大小写转换

一 大小写转换 1第1个单词的首字母大写 capitalize() 2每个单词的首字母大写 title() 3所有字母大小写转换 swapcase() 代码示例 texttoday is sundaYprint(text.capitalize()) # 仅第1个单词的首字母大写 print(text.title()) # 每个单词的首字母大写 print(text.swapcase…

Vue 多选下拉框+下拉框列表中增加标签

1、效果图 2、代码部分 &#xff08;1&#xff09;代码 <el-select class"common-dialog-multiple multipleSelectStyle" change"clusterListChange" v-model"form.clusterId" placeholder"请先选择" multiple filterable defaul…

【BUG】已解决:AttributeError: ‘str‘ object has no attribute ‘read‘

AttributeError: ‘str‘ object has no attribute ‘read‘ 目录 AttributeError: ‘str‘ object has no attribute ‘read‘ 【常见模块错误】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998https://bbs.csdn.net/topics/617804998 欢迎来到我的主…

(7) cmake 编译C++程序(二)

文章目录 概要整体代码结构整体代码小结 概要 在ubuntu下&#xff0c;通过cmake编译一个稍微复杂的管理程序 整体代码结构 整体代码 boss.cpp #include "boss.h"Boss::Boss(int id, string name, int dId) {this->Id id;this->Name name;this->DeptId …

error C2011: “sockaddr_in”:“struct”类型重定义的修改办法

问题 windows.h和winsock2.h存在有类型重定义,往往体现在头文件包含winsock2.h和windows.h时出现编译错误: error C2011: “sockaddr_in”:“struct”类型重定义 2>D:\Windows Kits\10\Include\10.0.22000.0\shared\ws2def.h(442,5): error C2143: 语法错误: 缺少“}”(…

为什么大家都想学大模型?一文揭秘!

小编只是普通的汽车软件工程师&#xff0c;想了解人工智能&#xff0c;又感觉好遥远&#xff0c;仔细的看了半天&#xff0c;就一个想法 好好拥抱AI吧。真的好强。 相比之下&#xff0c;Autosar 是个 der 啊。。。。 人工智能基础概念全景图 AI -> 机器学习 机器学习 ->…

探索 Python 的新视界:ttkbootstrap 库

探索 Python 的新视界&#xff1a;ttkbootstrap 库 背景与简介 在 Python 的世界中&#xff0c;库的丰富性是其强大功能的重要体现之一。今天&#xff0c;我们将一起探索一个令人兴奋的库——ttkbootstrap。这个库不仅提供了丰富的界面组件&#xff0c;还使得界面设计变得简单…

Python脚本批量下载ECWMF免费数据教程

前情提要 最近需要使用EC的一些数据&#xff0c;摸索下载过程中顺便记录下来&#xff0c;综合了EC上免费数据集的两个数据集的下载方式&#xff0c;使用python脚本下载 相比在网站上操作下载&#xff0c;个人更推荐脚本下载&#xff0c;官方已经封装好了两个库直接可以方便使…

HTML5实现好看的天气预报网站源码

文章目录 1.设计来源1.1 获取天气接口1.2 PC端页面设计1.3 手机端页面设计 2.效果和源码2.1 动态效果2.2 源代码 源码下载万套模板&#xff0c;程序开发&#xff0c;在线开发&#xff0c;在线沟通 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_4…

Django+vue自动化测试平台(27)-- 封装websocket测试

websocket概述&#xff1a; WebSocket 是一种在单个 TCP 连接上进行全双工通信(Full Duplex 是通讯传输的一个术语。通信允许数 据在两个方向上同时传输&#xff0c;它在能力上相当于两个单工通信方式的结合。全双工指可以同时&#xff08;瞬时&#xff09;进 行信号的双向传输…

Linux第四节课(指令与权限)

1、date指令(时间) 程序运行到自己的每一个关键时刻&#xff0c;都要自己打日志&#xff01; 日志包括时间、日志等级、日志具体信息、其他信息等&#xff0c;然后按照行为单位写入文件中&#xff0c;这个文件被称为日志文件&#xff01; 在日志文件中筛选信息时&#xff0c…

idea springBoot启动时覆盖apollo配置中心的参数

vm options -Dorder.stat.corn“0/1 * * * * ?” 只有vm options, -D参数才能覆盖apollo参数 program arguments –key01val01 --key02val02 environment varibales envFAT;key02val02;key03val03

视觉巡线小车——STM32+OpenMV(四)

目录 前言 一、整体控制思路 二、代码实现 1.主函数 2.定时器回调函数 总结 前言 通过以上三篇文章已将基本条件实现&#xff0c;本文将结合以上内容&#xff0c;进行综合控制&#xff0c;实现小车的视觉巡线功能。 系列文章请查看&#xff1a;视觉巡线小车——STM32OpenMV系列…

BUUCTF [WUSTCTF2020]朴实无华

首先进来不知道要干啥&#xff0c;上dirsearch扫出个机器人协议&#xff0c;一看有点东西 直接访问很明显这不是flag 主页面看他说什么不能修改头部&#xff0c;看一下数据包 发现了好东西 看到源码&#xff0c;又得绕过了。不过这编码有点问题导致乱码了 找个在线网站稍微恢复…

QtQuick-第一个程序

新建Qt Quick Application。 main.cpp(保持原有的即可): #include <QGuiApplication> #include <QQmlApplicationEngine>int main (int argc, char *argv[]) {QGuiApplication app (argc, argv);QQmlApplicationEngine engine;const QUrl url (QStringLiteral (&…

南平建网站公司推荐 好用的b2b独立站模板

床品毛巾wordpress独立站模板 床单、被套、毛巾、抱枕、靠垫、围巾、布艺、枕头、乳胶枕、四件套、浴巾wordpress网站模板。 https://www.jianzhanpress.com/?p4065 打印耗材wordpress自建独立站模板 色带、墨盒、碳粉、打印纸、硒鼓、墨盒、墨水、3D打印机、喷头wordpress…

基于 Apache 的 httpd 文件服务器

基于 Apache 的 httpd 文件服务器 文件服务器的简介 httpd&#xff08;HTTP Daemon&#xff0c;超文本传输协议守护进程的简称&#xff09;&#xff0c;运行于网页服务器后台&#xff0c;等待传入服务器请求的软件。 httpd 能够自动回应服务器的请求&#xff0c;并使用 http…

<PLC><Python>使用python与汇川PLC基于socket通讯程序:传感器数据传送与监控

前言 本系列是关于PLC相关的博文,包括PLC编程、PLC与上位机通讯、PLC与下位驱动、仪器仪表等通讯、PLC指令解析等相关内容。 PLC品牌包括但不限于西门子、三菱等国外品牌,汇川、信捷等国内品牌。 除了PLC为主要内容外,PLC相关元器件如触摸屏(HMI)、交换机等工控产品,如…