OAuth2.0

简介: OAuth2.0

OAuth2授权总体流程

  • 角色梳理:第三方应用 <------> 存储用户私密信息应用 -----> 授权服务器 ----》资源服务器
  • 整体授权流程:(图片来自RF6749文档)

四种授权模式

授权码模式

授权码模式(Authorization Code)是功能最完整、流程最严密、最安全并且使用最广泛的一种OAuth2授权模式,同事也是最复杂的一种授权模式,他的特点是通过客户端的后台服务器,于服务提供商的认证服务器进行互动,器具体的授权流程如图

  • Third-party application:第三方应用程序,简称“客户端”(client)
  • Resource Owner:资源所有者 简称用户(user)
  • User Agent:用户代理,是指浏览器;
  • Authorization Server:认证服务器,机服务端专门用来处理认证的服务器
  • Resource Server:资源服务器,即服务端存放用户生成的资源服务器,他与认证服务器,可以是同一个服务器,也可以是不同的服务器。

简单模式


密码模式

密码模式中,用户向客户端提供自己的用户名和密码,客户端使用这些信息,向“服务提供商”索要授权

具体步骤如下:

  • (A)用户向客户端提供用户名和密码
  • (B)客户端将用户名和密码发送给认证服务器,向后者请求令牌
  • (C)认证服务器确认无误后,向客户端提供访问令牌

核心参数:

https://wx.com/token?grant_type=password&username=USERNAME&password=PASSWORD&CLient_id=CLIENT_ID

客户端模式

OAuth2 标准接口

GitHub授权登录

创建Oauth应用

访问github并登录,在https://github.com/settings/profile中找到Developer Settings选项

  • 创建OAuth app并输入基本信息

项目开发

创建controller

/**
 * @Description:
 * @Author: Guo.Yang
 * @Date: 2022/11/12/23:49
 */
@RestController
public class HelloController {
    /**
     * DefaultOAuth2User说明
     * 只要是OAuth授权认证之后返回的都是DefaultOAuth2User 对象 里边存贮的是用户的信息
     *
     * @return
     */
    @RequestMapping("/hello")
    public DefaultOAuth2User hello(){
        System.out.println("hello");
        // springsecurity认证后就会吧用户信息存在 SecurityContextHolder 中 (springsecurity中提到)
        // 可以直接在 SecurityContextHolder 中拿到用户的基本信息
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        return (DefaultOAuth2User) authentication.getPrincipal();
    }
}
  • 配置 security
// 配置SpringSecurity 自定义配置
@Configuration
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .oauth2Login(); // 使用 oauth2 认证 , 配置文件中的配置认证服务
        }
    }
  • 配置文件
server:
  port: 8080
spring:
  application:
    name: springsecurity-oauth2-client-github
#    配置oauth2
  security:
    oauth2:
      client:
        registration:
          github:
#            连接id
            client-id: b0e485699b7fe9abe7e0
#            连接密钥
            client-secret: 22c5861091d17ce16416b35a976ebbbeb8ab4e9e
#            授权回调地址
            redirect-uri: http://localhost:8080/login/oauth2/code/github
  • 启动测试
  • 点击github 登录,点击授权就会跳转至我们刚才在github配置的应用首页,再次点击to hello 即可访问到我们应用的/hello资源

  • 测试通过

说明: 在整个过程中,颁发授权码,重定向授权回调地址、授权码获取令牌整个过程都是不可见的,过程可能更抽象一些。

OAuth源码相关认证过滤器

  • OAuth2AuthorizationCodeGrantFilter ---  处理OAuth2认证授权码
  • OAuth2LoginAuthenticationFilter --- 处理OAuth2认证




  • 真正的认证的过滤器:
  • OAuth2LoginAuthenticationFilter中的
  • attemptAuthentication()方法

Spring Security OAuth2

授权、资源服务器

授权服务器搭建

1. 基于内存客户端和令牌存储

创建 springboot 应用,并引入资源

注意:降低 springboot 版本为2.2.5.RELEASE

<!--引入授权服务器的依赖-->
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-oauth2</artifactId>
  <version>2.2.5.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
</dependency>
  • 编写配置类,添加security 配置类以及oauth配置类
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    // 由于授权服务器的密钥是不可以明文存贮的,只可以是加密以后,所以在此添加密码加密方式
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
    /**
     * 配置security请求
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().authenticated()
                .and().formLogin()
                .and().csrf().disable();
    }
    /**
     * 配置内存用户
     * 用户名:root
     * 密码:123
     * 权限:ADMIN
     * @return
     */
    public UserDetailsService userDetailsService(){
        InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
        inMemoryUserDetailsManager.createUser(User.withUsername("root").password("{noop}123").roles("ADMIN").build());
        return inMemoryUserDetailsManager;
    }
    /**
     * 配置用户名密码使用内存存储的
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService());
    }
}
/**
 * @Description: 授权服务器配置
 * @Author: Guo.Yang
 * @Date: 2022/11/13/21:28
 */
@Configuration
@EnableAuthorizationServer // 指定当前应用为授权服务器
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    // 因为密钥不可以使用明文,所以后期修改时,将其注入进来
    @Autowired
    private PasswordEncoder passwordEncoder;
    /**
     * 用来配置授权服务器i可以为那些客户端授权
     * @param clients
     * @throws Exception
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient("client") // id
                // .secret("secret") // 密钥
                .secret(passwordEncoder.encode("secret")) // 加密方式加密密钥,因为密钥不可以使用明文
                .redirectUris("https://www.baidu,com") // 重定向的uri
                .authorizedGrantTypes("authorization_code") // 授权服务器支持的模式 当前配置为 仅支持授权码模式
                .scopes("read:user"); // 令牌允许获取资源的权限
    }
}

授权码这种模式

  • 请求用户是否授权 /oauth/authorize
  • 授权之后根据获取的授权码获取令牌 /oauth/token

2.授权码模式测试

  1. 1.启动服务,登录之后进行授权码获取
  2. 完整路径为
http://localhost:8080/oauth/authorize?client_id=client&response_type=code&redirect_uri=https://www.baidu.com
  1. 2.点击授权后,跳转至重定向的uri并会在地址的后边携带上授权码 code
  2. 3.授权之后根据获取的授权码获取令牌 /oauth/token  参数有:id、secret、redirectUri、code

完整路径为:

curl --location --request POST 'http://client:secret@localhost:8080/oauth/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Cookie: JSESSIONID=9B99A4E09092B73EF32FFC3FF7630DAA' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'code=ytDyI7' \
--data-urlencode 'redirect_uri=http://www.baidu.com'

注意:

  • 当前访问之后并不会返回accesstoken,会报错,
  • 由于我们在配置springsecurity账号密码的时候设置的是明文的方式
  • 而在我们的授权服务的配置中 密钥也同样是明文,这样是不可以的
  • 正确的做法添加加密方式
  • 在springsecurityconfig配置密码加密方式
@Bean
public PasswordEncoder passwordEncoder(){
    return new BCryptPasswordEncoder();
}
  • 在AuthorizationServerConfig中将 PasswordEncoder 注入进来,并加密密钥
  • 正确的获取令牌的路径
curl --location --request POST 'http://client:secret@localhost:8080/oauth/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Cookie: JSESSIONID=9B99A4E09092B73EF32FFC3FF7630DAA' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'code=elPsoG' \
--data-urlencode 'redirect_uri=https://www.baidu.com'

3、密码模式测试

  • 需要在授权配置类中开启oauth对密码模式的支持
  • 需要在SpringSecurityConfig配置类中将 AuthenticationManager暴露出来 重写authenticationManager 并添加Bean
    /**
     * 密码模式所需
     * 暴露出 AuthenticationManager
     * @return
     * @throws Exception
     */
    @Override
    @Bean
    protected AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager()  ;
    }
  • 在 AuthorizationServerConfig(授权配置类)中添加认证authenticationManager
    /**
     * 配置授权服务器使用那个 userDetailService
     * @param endpoints
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager); // 注入 认证authenticationManager
    }

  • 测试
curl --location --request POST 'http://client:secret@localhost:8080/oauth/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Cookie: JSESSIONID=9B99A4E09092B73EF32FFC3FF7630DAA' \
--data-urlencode 'grant_type=password' \
--data-urlencode 'username=root' \
--data-urlencode 'password=123'

基于数据库的客户端、令牌存储

简表语句

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for clientdetails
-- ----------------------------
DROP TABLE IF EXISTS `clientdetails`;
CREATE TABLE `clientdetails` (
  `appId` varchar(256) NOT NULL,
  `resourceIds` varchar(256) DEFAULT NULL,
  `appSecret` varchar(256) DEFAULT NULL,
  `scope` varchar(256) DEFAULT NULL,
  `grantTypes` varchar(256) DEFAULT NULL,
  `redirectUrl` varchar(256) DEFAULT NULL,
  `authorities` varchar(256) DEFAULT NULL,
  `access_token_validity` int(11) DEFAULT NULL,
  `refresh_token_validity` int(11) DEFAULT NULL,
  `additionalInformation` varchar(4096) DEFAULT NULL,
  `autoApproveScopes` varchar(256) DEFAULT NULL,
  PRIMARY KEY (`appId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Table structure for oauth_access_token
-- ----------------------------
DROP TABLE IF EXISTS `oauth_access_token`;
CREATE TABLE `oauth_access_token` (
  `token_id` varchar(256) DEFAULT NULL,
  `token` blob,
  `authentication_id` varchar(256) NOT NULL,
  `user_name` varchar(256) DEFAULT NULL,
  `client_id` varchar(256) DEFAULT NULL,
  `authentication` blob,
  `refresh_token` varchar(256) DEFAULT NULL,
  PRIMARY KEY (`authentication_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Table structure for oauth_approvals
-- ----------------------------
DROP TABLE IF EXISTS `oauth_approvals`;
CREATE TABLE `oauth_approvals` (
  `userId` varchar(256) DEFAULT NULL,
  `clientId` varchar(256) DEFAULT NULL,
  `scope` varchar(256) DEFAULT NULL,
  `status` varchar(10) DEFAULT NULL,
  `expiresAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `lastModifiedAt` date DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Table structure for oauth_client_details
-- ----------------------------
DROP TABLE IF EXISTS `oauth_client_details`;
CREATE TABLE `oauth_client_details` (
  `client_id` varchar(256) NOT NULL,
  `resource_ids` varchar(256) DEFAULT NULL,
  `client_secret` varchar(256) DEFAULT NULL,
  `scope` varchar(256) DEFAULT NULL,
  `authorized_grant_types` varchar(256) DEFAULT NULL,
  `web_server_redirect_uri` varchar(256) DEFAULT NULL,
  `authorities` varchar(256) DEFAULT NULL,
  `access_token_validity` int(11) DEFAULT NULL,
  `refresh_token_validity` int(11) DEFAULT NULL,
  `additional_information` varchar(4096) DEFAULT NULL,
  `autoapprove` varchar(256) DEFAULT NULL,
  PRIMARY KEY (`client_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Table structure for oauth_client_token
-- ----------------------------
DROP TABLE IF EXISTS `oauth_client_token`;
CREATE TABLE `oauth_client_token` (
  `token_id` varchar(256) DEFAULT NULL,
  `token` blob,
  `authentication_id` varchar(256) NOT NULL,
  `user_name` varchar(256) DEFAULT NULL,
  `client_id` varchar(256) DEFAULT NULL,
  PRIMARY KEY (`authentication_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Table structure for oauth_code
-- ----------------------------
DROP TABLE IF EXISTS `oauth_code`;
CREATE TABLE `oauth_code` (
  `code` varchar(256) DEFAULT NULL,
  `authentication` blob
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Table structure for oauth_refresh_token
-- ----------------------------
DROP TABLE IF EXISTS `oauth_refresh_token`;
CREATE TABLE `oauth_refresh_token` (
  `token_id` varchar(256) DEFAULT NULL,
  `token` blob,
  `authentication` blob
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
SET FOREIGN_KEY_CHECKS = 1;

配置客户端

令牌颁发配置


相关文章
|
机器学习/深度学习 TensorFlow API
基于CNN的图像识别(Tensorflow)
基于CNN的图像识别(Tensorflow)
|
人工智能 数据可视化 数据挖掘
Quick BI 体验&征文有奖!
瓴羊生态推出Quick BI 征文激励计划,鼓励用户分享数据分析实践经验与技术洞察,征集高质量原创文章。内容围绕AI功能体验与BI案例实践,设季奖、年奖及参与奖,优秀作者可获现金奖励、产品内测资格及官方认证形象。投稿截止至2026年3月31日。
Quick BI 体验&征文有奖!
|
数据安全/隐私保护
OAuth 2.0身份验证及授权
8月更文挑战第24天
736 0
|
11月前
|
编解码 Cloud Native 算法
通义万相:视觉生成大模型再进化
通义万相是阿里云推出的视觉生成大模型,涵盖图像和视频生成。其2.0版本在文生图和文生视频方面进行了重大升级,采用Diffusion Transformer架构,提升了模型的灵活性和可控性。通过高质量美学标准和多语言支持,大幅增强了画面表现力。此外,视频生成方面引入高压缩比VAE、1080P长视频生成及多样化艺术风格支持,实现了更丰富的创意表达。未来,通义万相将继续探索视觉领域的规模化和泛化,打造更加通用的视觉生成大模型。
|
机器学习/深度学习 测试技术 计算机视觉
NeurIPS 2024:FaceChain团队新作,开源拓扑对齐人脸表征模型TopoFR
在2024年NeurIPS会议上,FaceChain团队推出TopoFR模型,通过利用数据的拓扑结构信息,显著提升了人脸识别的准确性。TopoFR采用PTSA策略和SDE策略,分别增强了模型的泛化能力和对硬样本的处理效果。实验结果显示,TopoFR在多个基准测试中表现优异,特别是在IJB-C和IJB-B等高难度测试中,显著超越了现有方法。
458 5
|
监控 API 数据安全/隐私保护
2024年开源API工具盘点,覆盖API全生命周期
2024年经济持续低迷,本文整理一些免费的开源工具,旨在帮助企业组织降低工具的支出成本,能用免费的何必用付费的呢(狗头)?
645 0
|
存储 数据采集 监控
Telegraf 使用小结
Telegraf 使用小结
320 1
|
机器学习/深度学习 Shell
【从零开始学习深度学习】22. 卷积神经网络(CNN)中填充(padding)与步幅(stride)详解,填充、步幅、输入及输出之间的关系
【从零开始学习深度学习】22. 卷积神经网络(CNN)中填充(padding)与步幅(stride)详解,填充、步幅、输入及输出之间的关系
|
安全 数据安全/隐私保护 UED
|
数据格式
【新特性演示】YOLOv8实现旋转对象检测
【新特性演示】YOLOv8实现旋转对象检测
890 0