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;

配置客户端

令牌颁发配置


相关文章
|
SQL 数据库 数据安全/隐私保护
Sql Server数据库Sa密码如何修改
Sql Server数据库Sa密码如何修改
1002 0
|
数据采集 测试技术 数据安全/隐私保护
Playwright测试中避免使用no-wait-for-timeout的原因
在Web应用自动化测试中,Playwright作为首选框架,其稳定性至关重要。不当使用`no-wait-for-timeout`会导致测试结果不稳定、不符合真实用户体验且难以调试。推荐采用显式等待策略和合理设置超时时间,结合代理IP技术提高测试成功率和数据多样性。示例代码展示了如何在Playwright中配置代理IP进行数据抓取及分类统计。遵循这些最佳实践可确保测试既可靠又贴近实际用户场景。
702 4
Playwright测试中避免使用no-wait-for-timeout的原因
|
10月前
|
负载均衡 算法 Go
GoLang协程Goroutiney原理与GMP模型详解
【11月更文挑战第4天】Goroutine 是 Go 语言中的轻量级线程,由 Go 运行时管理,创建和销毁开销小,适合高并发场景。其调度采用非抢占式和协作式多任务处理结合的方式。GMP 模型包括 G(Goroutine)、M(系统线程)和 P(逻辑处理器),通过工作窃取算法实现负载均衡,确保高效利用系统资源。
197 3
|
11月前
|
人工智能 语音技术 UED
仅用4块GPU、不到3天训练出开源版GPT-4o,这是国内团队最新研究
【10月更文挑战第19天】中国科学院计算技术研究所提出了一种名为LLaMA-Omni的新型模型架构,实现与大型语言模型(LLMs)的低延迟、高质量语音交互。该模型集成了预训练的语音编码器、语音适配器、LLM和流式语音解码器,能够在不进行语音转录的情况下直接生成文本和语音响应,显著提升了用户体验。实验结果显示,LLaMA-Omni的响应延迟低至226ms,具有创新性和实用性。
397 1
|
存储 安全 Java
OAuth2
OAuth2
186 0
|
数据安全/隐私保护
OAuth 2.0身份验证及授权
8月更文挑战第24天
606 0
无缝构建与部署:GitLab CI/CD首秀的实战攻略
无缝构建与部署:GitLab CI/CD首秀的实战攻略
312 0
无缝构建与部署:GitLab CI/CD首秀的实战攻略
|
存储 安全 Java
接入OAuth2
接入OAuth2
205 0
|
前端开发
CSS实现鼠标放上去显示提示工具
CSS实现鼠标放上去显示提示工具
152 0
|
消息中间件 存储 设计模式