oauth2授权码模式单点登录

news2024/11/26 23:36:36

文章目录

  • 前言
  • 一、单点登录是什么?
  • 二、oauth2授权码模式单点登录流程
    • 1.流程图
    • 2. 代码相关
    • 2. 验证流程
  • 总结


前言

oauth2 有四种模式,常用的为密码和授权码,剩下两种几乎不用

  1. 密码模式,很好理解,就是根据输入的用户名/密码进行登录认证的,最终返回一个合法token
  2. 授权码(grant_type = authorization_code), 是利用唯一的客户端信息,申请的一个临时授权码,然后根据授权码换取合法token,可以利用这个特性,达到单点登录的效果

一、单点登录是什么?

简而言之: 登录一次,可以访问所有当前网站被信任的其他网站,无需再次登录;
例如:

我登录了淘宝,然后再次访问里面的其他应用的时候,不会再次登录,而是直接就进去了(天猫 聚划算 咸鱼)

二、oauth2授权码模式单点登录流程

1.流程图

授权码登录流程

操作步骤说明:

  1. 用户访问服务A,需要使用服务提供商的数据(用户信息),首次访问没有任何信息,需要登录;
  2. 服务A通过重定向跳转到服务提供商的统一登录页面。在重定向中构建授权码请求,授权许可
  3. 用户选择是否给予客户端授权访问服务提供商(用户信息)数据的权限
  4. 输入用户信息,用户给予授权。权限系统通过重定向(redirect_uri)并携带 授权凭证(code)跳转客户端。
  5. 服务A提供redirect_uri的接口,接受授权码code,将授权凭证(code)发送给鉴权中心服务器,服务A服务器携带授权码(code)、客户端id(client_id)和秘钥(client_secret)向认证服务器请求访问令牌(access_token)
  6. 鉴权中心认证服务器核对授权码信息,确认无误后,向客户端发送访问令牌(access_token)和更新令牌(refresh_token)
  7. 客户端持有访问令牌(access_token)和需要请求的参数向服务A发起资源请求,服务A拿着token去鉴权中心校验,无误后将资源返回给客户端
  8. 客户端访问受信任的服务B,发现服务B未授权,携带服务B的url去鉴权中心
  9. 去鉴权中心鉴权,发现该用户已经登录,token有效,重定向到服务B的redirect_uri,直接签发已有token,授权资源
    10.客户端携带token 访问服务B

2. 代码相关

pom

  • 鉴权中心
<dependency>
	<groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!--
 注意:spring-cloud-starter-oauth2中包含spring-cloud-starter-security和spring-security-oauth2-autoconfigure
 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
  • 服务A

与上面一直

配置

  • 鉴权中心
    标记为鉴权服务中心

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    // 令牌端点的安全约束
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security
                // 允许表单登录
                .allowFormAuthenticationForClients()
                // 公开token
                .tokenKeyAccess("permitAll()")
                // 全部允许验证token
                .checkTokenAccess("permitAll()");
    }
    

    // 用内存存储
    // 自动创建UserDetailsServiceInfo实例
    @Autowired
    private UserDetailsServiceInfo userDetailsServiceInfo;
    // 自动加载WebSecurityConfig中的authenticationManagerBean()方法的返回值AuthenticationManager对象
    @Autowired
    private AuthenticationManager authenticationManager;
    // 令牌端点配置
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        super.configure(endpoints);
        // 认证管理器,密码模式时使用
        endpoints.authenticationManager(this.authenticationManager)
                // 会自动调用UserDetailsServiceInfo下的loadUserByUsername()方法
                .userDetailsService(this.userDetailsServiceInfo);
    }
    
    // 自动加载WebSecurityConfig中的bcryptPasswordEncoder()方法的返回值BCryptPasswordEncoder对象
    @Autowired
    private PasswordEncoder bcryptPasswordEncoder;
    // 客户端信息配置
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                // 客户端名称
                .withClient("web")
                // 客户端密钥
                .secret(this.bcryptPasswordEncoder.encode("123456"))
                // 设置授权模式为password
                .authorizedGrantTypes("password", "refresh_token")
                .scopes("all")
                // 设置token有效期
                .accessTokenValiditySeconds(920)
                // 设置刷新token的有效期
                .refreshTokenValiditySeconds(920)
                .autoApprove(true)

                .and()

                // 客户端名称
                .withClient("app")
                // 客户端密钥
                .secret(this.bcryptPasswordEncoder.encode("123456"))
                // 设置授权模式为password
                .authorizedGrantTypes("password", "authorization_code", "refresh_token")
                .scopes("all")
                // 设置token有效期
                .accessTokenValiditySeconds(920)
                // 设置刷新token的有效期
                .refreshTokenValiditySeconds(920)
                // 配置授权码模式必须配置uri,否则授权后跳转无权限
                .redirectUris("http://127.0.0.1:8082/data/common")
                .autoApprove(true);

    }

}

security,web启用

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    // 用户权限管理器,进行用户认证,配置用户签名服务和用户权限控制
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }


    // 将BCryptPasswordEncoder对象注入Spring容器中,
    // SpringSecurity会使用PasswordEncoder自动密码校验
    @Bean
    public PasswordEncoder bcryptPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }

    // 用户授权,配置拦截请求、请求验证、异常处理
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //关闭csrf
        http.csrf().disable();

        // 解决跨域
        http.cors();

        // 开启Spring Security默认的表单登录
        http.formLogin();
                // 根据需求,自定义登录页面,注意不要拦截此Action
//              .loginPage("/login");

        // 设置认证的action
        http.authorizeRequests()
                // 不拦截以下action
                .antMatchers("/sso/register").permitAll()

                // 处了上面的action,都需要鉴权认证
                .anyRequest().authenticated();
    }


}

自定义认证过程

@Service
public class UserDetailsServiceInfo implements UserDetailsService {

    // 自动加载WebSecurityConfig中的bcryptPasswordEncoder()方法的返回值BCryptPasswordEncoder对象
    @Autowired
    private PasswordEncoder bcryptPasswordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // (1)根据username查询数据库,找到账号和密码,下面类似查数据库
        if (!"admin".equals(username)){
            // 查不到数据返回null即可
            return null;
        }

        // (2) 对查询的密码进行加密,如果数据库的密码已经加密,此处不做。
        String password = this.bcryptPasswordEncoder.encode("123456");

        // (3) 生成User对象

        /*
        // 使用userdetails自带的UserDetails的对象User
        User user = new User("admin",password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin, secretary"));
        return user;
        */

        // 使用自定义的UserDetails对象UserDetailsInfo
        UserDetailsInfo userDetailsInfo = new UserDetailsInfo("1","admin", password, null);
        return userDetailsInfo;

    }

}
  • 服务A
    标记为资源服务提供者
@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {

        //关闭csrf
        http.csrf().disable();

        // 解决跨域
        http.cors();

        // 登录,此处可以不设置,默认会跳转到SpringSecurity的登录页面
//        http.formLogin();

        // 设置认证的action
        http.authorizeRequests()
                // 不拦截以下action
                .antMatchers("/data/common")
                .permitAll()

                // 处了上面的action,都需要鉴权认证
                .anyRequest().authenticated();

    }


}

yml

server:
  port: 8082

security:
  oauth2:
    client:
      # 配置授权服务器参数
      client-id: web
      client-secret: 123456
      # 配置获取token
      access-token-uri: http://127.0.0.1:8080/oauth/token
      # 配置授权码模式认证,如果只有密码模式,此处可以不配置
      # user-authorization-uri: http://127.0.0.1:8080/oauth/authorize

    resource:
      # 验证Token,并返回客户端信息
      token-info-uri: http://127.0.0.1:8080/oauth/check_token

2. 验证流程

最终能获取到一个合法token,并且成功访问到资源

  1. 获取code
  2. 根据code获取token
  3. 携带token访问资源,成功

总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

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

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

相关文章

Coze:如何使用主页对话框?

你好&#xff0c;我是三桥君 我们今天要介绍的功能模块是“主页对话框”。 目录 访问官网 登录首页 基本功能 主页对话框 第一个功能&#xff1a;如何与自己收藏的机器人进行对话&#xff1f; 第二个功能&#xff1a;如何请求主页对话框的机器人帮助创建一个新的机器人&#x…

C++11 异步操作 std::future类

阅读导航 引言一、异步的概念二、应用场景1. 异步任务处理2. 并发控制3. 结果获取 三、使用示例1. 使用std::async关联异步任务&#x1f4bb;示例代码说明 2. 使用std::packaged_task和std::future配合&#xff08;1&#xff09;定义std::packaged_task&#xff08;2&#xff0…

游戏修改器Cheat Engine CE v7.5修改版下载安装详细方法

Cheat Engine是一个专注于游戏的修改器。它可以用来扫描游戏中的内存&#xff0c;并允许修改它们。它还附带了调试器、反汇编器、汇编器、变速器、作弊器生成、Direct3D操作工具、系统检查工具等。 具体安装方法如下&#xff1a; 地址&#xff1a;Cheat Engine 7.5.zip 解压文件…

Prompt 初级版:构建高效对话的基础指南

Prompt 初级版&#xff1a;构建高效对话的基础指南 文章目录 Prompt 初级版&#xff1a;构建高效对话的基础指南一 “标准”提示二 角色提示三 多范例提示四 组合提示五 规范化提示 本文介绍了提示词的基础概念与不同类型&#xff0c;帮助用户更好地理解如何在对话中构建有效的…

Java 计算器项目

更多有趣请关注公众号 计算器项目 代码仓库&#xff1a;https://gitee.com/wengxiulin/vs_code 项目图片 项目简介 这是一个用 Java 编写的简单计算器应用程序&#xff0c;具有基本的数学运算功能。该计算器支持加、减、乘、除等运算&#xff0c;并提供用户友好的图形界面…

CSP-J模拟赛三补题报告

前言 挂了110pts( ⇑ \Uparrow ⇑ \hspace{14em} 有史以来最大傻逼 T1&#xff1a; 100 p t s \color{green}100pts 100pts T2: 100 p t s → 80 p t s \color{green}100pts\color{yellow}\rightarrow\color{red}80pts 100pts→80pts T3: 100 p t s → 10 p t s \color{gre…

java 的三种IO模型(BIO、NIO、AIO)

java 的三种IO模型&#xff08;BIO、NIO、AIO&#xff09; 一、BIO 阻塞式 IO&#xff08;Blocking IO&#xff09;1.1、BIO 工作机制1.2、BIO 实现单发单收1.3、BIO 实现多发多收1.4、BIO 实现客户端服务端多对一1.5、BIO 模式下的端口转发思想 二、NIO 同步非阻塞式 IO&#…

【Godot4.3】模拟平面图形绕轴或点在空间旋转

概述 平面图形&#xff0c;除了常规的线性变换&#xff1a;平移、缩放、旋转、斜切之外。还可以模仿在三维空间旋转、透视等等。 矩形绕纵对称轴旋转实点的轨迹 绕对称旋转是个特殊情况&#xff0c;轨迹是圆也是为了便于理解。更实际的情况应该是椭圆。非对称轴旋转的情况轨…

Java 之深入理解 String、StringBuilder、StringBuffer

前言 由于发现 String、StringBuilder、StringBuffer 面试的时候会经常问到&#xff0c;这里就顺便总结一下&#xff1a;本文重点会以这三个字符串类的性能、线程安全、存储结构这三个方面进行分析 ✨上期回顾&#xff1a;Java 哈希表 ✨目录 前言 String 介绍 String 的不可变…

2024/10/3 408数据结构大题打卡

最短路径复习&#xff1a; bfs&#xff1a;只能解决无权图

【LeetCode每日一题】——17.电话号码的字母组合

文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【题目提示】七【解题思路】八【时间频度】九【代码实现】十【提交结果】 一【题目类别】 回溯 二【题目难度】 中等 三【题目编号】 17.电话号码的字母组合 四【题目描述】 给定一个…

redis 5的安装及启动(window)

最近看大模型的时候发现入手redis的同学没有练手的&#xff0c;而且大部分redis的文章要钱才能看&#xff0c;在这里我把路径和环境配置&#xff0c;启动给大家说一下 下载 redis5的获取链接在下面&#xff08;为什么是redis5&#xff0c;因为上个模型用的就是redis5&#xff…

pipe函数的例子

代码&#xff1a; #include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<sys/types.h> int main(void) {int result -1;int fd[2],nbytes;pid_t pid;char string[80]"ni hao, pipe!";char readbuff…

linux信号 | 学习信号四步走 | 一篇文章教你理解信号如何保存

前言&#xff1a; 本节内容是信号的保存。 学习信号&#xff0c; 我们首先了解了信号的概念&#xff0c; 然后学习了信号的产生方式。 现在就开始讲解信号在时间窗口内是如何保存在进程内部的。 ps&#xff1a;本节内容需要了解信号的概念&#xff0c; 希望友友们了解一些信号…

实用技能分享!推荐最适合论文写作的5款ai工具

在当今学术研究和教育领域&#xff0c;AI工具的应用已经变得越来越普遍。这些工具不仅能够提高写作效率&#xff0c;还能帮助生成高质量的文稿。对于教师而言&#xff0c;选择合适的AI工具可以显著提升论文写作的效率和质量。本文将重点推荐五款最适合教师论文写作的AI工具&…

Linux聊天集群开发之环境准备

一.windows下远程操作Linux 第一步&#xff1a;在Linux终端下配置openssh&#xff0c;输入netstate -tanp,查看ssh服务是否启动&#xff0c;默认端口22.。 注&#xff1a;如果openssh服务&#xff0c;则需下载。输入命令ps -e|grep ssh, 查看如否配有&#xff0c; ssh-agent …

【重学 MySQL】四十六、创建表的方式

【重学 MySQL】四十六、创建表的方式 使用CREATE TABLE语句创建表使用CREATE TABLE LIKE语句创建表使用CREATE TABLE AS SELECT语句创建表使用CREATE TABLE SELECT语句创建表并从另一个表中选取数据&#xff08;与CREATE TABLE AS SELECT类似&#xff09;使用CREATE TEMPORARY …

【重学 MySQL】五十四、整型数据类型

【重学 MySQL】五十四、整型数据类型 整型类型TINYINTSMALLINTMEDIUMINTINT&#xff08;或INTEGER&#xff09;BIGINT 可选属性UNSIGNEDZEROFILL显示宽度&#xff08;M&#xff09;AUTO_INCREMENT注意事项 适合场景TINYINTSMALLINTMEDIUMINTINT&#xff08;或INTEGER&#xff0…

Python 从入门到实战33(使用MySQL)

我们的目标是&#xff1a;通过这一套资料学习下来&#xff0c;通过熟练掌握python基础&#xff0c;然后结合经典实例、实践相结合&#xff0c;使我们完全掌握python&#xff0c;并做到独立完成项目开发的能力。 上篇文章我们讨论了数据库编程接口操作的相关知识。今天我们将学习…

SLF4J(W): Class path contains multiple SLF4J providers.

问题背景 最近在给某AI项目集成阿里的通义千问SDK&#xff0c;发现竟然有个奇怪的报错&#xff0c;仔细一看发现&#xff0c;我类上用的lombok的Slf4j注释&#xff0c;阿里用的是org.slf4j.simple.SimpleServiceProvider&#xff0c;但是lombok用的是LogbackServiceProvider&a…