首页 > 其他分享 >OAuth2 原理与机制详解及应用案例

OAuth2 原理与机制详解及应用案例

时间:2024-11-01 23:18:01浏览次数:6  
标签:令牌 OAuth2 JWT 验证码 案例 详解 phoneNumber 授权

一、OAuth2 简介

1.1 什么是 OAuth2?

  • 定义:OAuth2(Open Authorization)是一种用于安全授权的开放标准协议。
  • 作用:允许第三方应用安全地访问用户资源,而无需暴露用户的身份凭证。

1.2 OAuth2 的基本概念

  • Resource Owner(资源拥有者):通常是用户。
  • Client(客户端):需要访问用户资源的应用程序。
  • Resource Server(资源服务器):存储用户资源并提供受保护资源访问接口的服务器。
  • Authorization Server(授权服务器):负责验证用户身份并向客户端颁发访问令牌。

1.3 OAuth2 的应用场景

  • 适用于单点登录(SSO)、开放平台授权以及移动应用和第三方Web服务集成。

二、OAuth2 认证流程

2.1 四种授权方式

  1. 授权码模式(Authorization Code):适合服务器端应用。
  2. 简化模式(Implicit):适用于客户端应用。
  3. 密码模式(Resource Owner Password Credentials):适合用户信任的应用。
  4. 客户端凭证模式(Client Credentials):适合服务与服务之间的通信。

2.2 授权码模式流程分析

授权码模式较为常见,主要流程如下:

  1. 用户授权请求:客户端将用户重定向到授权服务器,用户登录并授予权限。
  2. 返回授权码:授权服务器重定向回客户端并携带授权码。
  3. 交换令牌:客户端使用授权码向授权服务器请求令牌。
  4. 访问资源:客户端使用令牌访问资源服务器上的受保护资源。

2.3 时序图

在这里插入图片描述

三、OAuth2 授权机制详解

3.1 访问令牌(Access Token)

  • 访问令牌是 OAuth2 认证的关键,通常是短生命周期的随机字符串。
  • 存储方式:常见存储方法有JWT(JSON Web Token)和Opaque Token。

3.2 刷新令牌(Refresh Token)

  • 作用:延长授权时间,通过刷新令牌请求新的访问令牌。
  • 使用场景:当访问令牌过期时,客户端可以使用刷新令牌重新获取授权。

3.3 令牌的存储与安全

  • 建议加密存储令牌,避免令牌泄露。
  • 在客户端使用 HTTPS 进行传输,防止中间人攻击。

四、Spring Boot 集成 OAuth2 和 JWT:实现短信验证登录

4.1 架构概述

在这次实现中,我们将使用 OAuth2 认证流程并结合 JWT 进行用户身份验证。用户通过短信验证码登录,经过验证后,生成 JWT 令牌,供前端用于后续请求。

流程如下:

  1. 请求验证码:用户在前端输入手机号,前端请求验证码接口。
  2. 验证码校验:后端生成验证码并存储在缓存中。
  3. 登录验证:前端发送验证码与手机号,后端校验验证码,生成 JWT 令牌。
  4. 后续请求验证:后续接口需附带 JWT 进行验证。

4.2 项目配置

pom.xml 中引入必要的依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

4.3 JWT 配置

application.yml 中配置 JWT 私钥和过期时间:

jwt:
  secret: mySecretKey
  expiration: 3600 # 1小时,单位秒

4.4 发送短信验证码接口

实现短信服务

此接口生成验证码并缓存,实际中可以使用 Redis 实现缓存。

@RestController
@RequestMapping("/auth")
public class AuthController {

    private final Map<String, String> smsCache = new HashMap<>(); // 临时缓存模拟

    @GetMapping("/send-sms")
    public ResponseEntity<?> sendSmsCode(@RequestParam String phoneNumber) {
        String code = String.valueOf((int)((Math.random() * 9 + 1) * 1000));
        smsCache.put(phoneNumber, code);
        // 真实场景中需调用短信发送服务,如阿里云、Twilio
        System.out.println("SMS Code for " + phoneNumber + " is " + code);
        return ResponseEntity.ok("验证码已发送");
    }
}

4.5 验证验证码并生成 JWT 令牌

在该接口中,校验验证码是否正确,正确则生成 JWT 令牌:

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

@RestController
@RequestMapping("/auth")
public class AuthController {

    @Value("${jwt.secret}")
    private String secret;

    @Value("${jwt.expiration}")
    private long expiration;

    @PostMapping("/login")
    public ResponseEntity<?> login(@RequestParam String phoneNumber, @RequestParam String code) {
        if (!smsCache.containsKey(phoneNumber) || !smsCache.get(phoneNumber).equals(code)) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("验证码错误");
        }
        String token = generateToken(phoneNumber);
        return ResponseEntity.ok(Collections.singletonMap("token", token));
    }

    private String generateToken(String phoneNumber) {
        Date now = new Date();
        Date expiryDate = new Date(now.getTime() + expiration * 1000);
        return Jwts.builder()
                .setSubject(phoneNumber)
                .setIssuedAt(new Date())
                .setExpiration(expiryDate)
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }
}

4.6 JWT 验证配置

SecurityConfig 中配置 JWT 过滤器,校验请求头中的 JWT 令牌。

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .authorizeRequests()
            .antMatchers("/auth/**").permitAll()
            .anyRequest().authenticated()
            .and()
            .oauth2ResourceServer()
            .jwt();
    }
}

4.7 前端代码示例(HTML + JavaScript)

以下代码展示如何通过 HTML 和 JavaScript 调用短信验证码和登录接口,并获取 JWT。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>SMS Login</title>
    <script>
        async function sendSms() {
            const phoneNumber = document.getElementById('phone').value;
            const response = await fetch(`/auth/send-sms?phoneNumber=${phoneNumber}`);
            const data = await response.text();
            alert(data);
        }

        async function login() {
            const phoneNumber = document.getElementById('phone').value;
            const code = document.getElementById('code').value;
            const response = await fetch('/auth/login', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded'
                },
                body: `phoneNumber=${phoneNumber}&code=${code}`
            });
            const data = await response.json();
            if (data.token) {
                alert("登录成功");
                localStorage.setItem('token', data.token);
            } else {
                alert("验证码错误");
            }
        }
    </script>
</head>
<body>
    <h2>短信验证码登录</h2>
    <input type="text" id="phone" placeholder="手机号" required>
    <button onclick="sendSms()">发送验证码</button>
    <br><br>
    <input type="text" id="code" placeholder="验证码" required>
    <button onclick="login()">登录</button>
</body>
</html>

五、OAuth2 安全性

5.1 HTTPS 加密传输

所有的令牌和用户数据都应通过 HTTPS 传输,以避免被中间人拦截或篡改。特别是在生产环境下,未加密的 HTTP 传输会导致敏感数据暴露。

5.2 访问令牌的存储与保护

  • 将访问令牌存储在客户端的安全存储中(如浏览器的 HttpOnly Cookie 中)以防止跨站点脚本攻击(XSS)。
  • 避免在 URL 中传递访问令牌。OAuth2 的 Authorization 头部是一种更为安全的传递方式,减少 URL 曝露令牌的风险。

5.3 限制令牌的生命周期

访问令牌应设置较短的有效期,推荐 10 分钟以内的生命周期,以减少令牌泄露后的风险。可使用刷新令牌来延长会话,以便在令牌失效后通过刷新令牌重新获取授权。

5.4 使用基于作用域的权限控制

OAuth2 支持定义令牌的访问作用域(Scope)。为提高安全性,应根据用户角色和 API 需求定义精确的权限范围,避免过度授权。示例如下:

spring:
  security:
    oauth2:
      client:
        registration:
          google:
            scope: profile, email  # 精细化权限控制

5.5 使用状态参数防止 CSRF 攻击

在 OAuth2 授权过程中,使用 state 参数来防止跨站请求伪造(CSRF)攻击。每次授权请求时,生成一个随机的 state 值,并在重定向后验证其一致性。

5.6 日志记录与监控

在 OAuth2 授权过程中记录关键操作日志(如授权请求、令牌交换、用户信息请求等),以便进行审计和分析。例如,可以在 Spring Boot 中使用日志工具记录请求信息和异常信息。

示例代码:记录授权请求日志
@RestController
public class AuthLoggingController {

    private static final Logger logger = LoggerFactory.getLogger(AuthLoggingController.class);

    @GetMapping("/oauth2/callback")
    public String callback(OAuth2AuthenticationToken authToken) {
        logger.info("User authenticated with OAuth2: {}", authToken.getPrincipal());
        return "You are authenticated!";
    }
}

5.7 授权服务器的防护

如果在应用中配置了自定义授权服务器(如通过 Spring Authorization Server 实现),则应额外注意以下几点:

  1. 防暴力破解:限制尝试登录的次数,防止凭证暴力破解。
  2. 防止重放攻击:为授权请求和令牌交换实现唯一的事务 ID,确保同一请求不会被重复处理。

标签:令牌,OAuth2,JWT,验证码,案例,详解,phoneNumber,授权
From: https://blog.csdn.net/weixin_39996520/article/details/143392057

相关文章

  • Git详解
    一、Git简介1.1Git是什么?Git是一个分布式版本控制系统,用于跟踪文件的变化,尤其是源代码的管理。它允许多个开发者协同工作,跟踪代码的版本和历史记录,方便项目的管理和维护。1.2Git的主要功能版本控制:记录文件的变化历史,方便恢复和比较。分支管理:轻松创建、合并和删......
  • Vue全家桶-Vue-Router详解
    前后端分离阶段URL的hashHTML5的History认识vue-routervue-router的使用路由的默认路径history模式router-link路由懒加载打包效果分析路由的其他属性动态路由基本匹配......
  • Java 缓冲流详解
    在Java的I/O体系中,缓冲流(BufferedStreams)是对字节流和字符流的一种封装,通过在内存中开辟缓冲区来提高I/O操作的效率。Java提供了BufferedInputStream和BufferedOutputStream来实现字节流的缓冲,以及BufferedReader和BufferedWriter来实现字符流的缓冲。本文......
  • Spring JdbcTemplate详解
    文章目录SpringJdbcTemplate详解一、引言二、配置JdbcTemplate1、引入依赖2、配置数据库连接池3、配置JdbcTemplate三、使用JdbcTemplate操作数据库1、添加数据2、查询数据查询某个值根据条件查询返回某个对象查询对象集合四、总结SpringJdbcTemplate详解一、......
  • grafana图表功能-06-监控指标详解
    一. prometheus的4种监控指标Counters计数器Gauges仪表/测量Histograms直方图Summaries汇总二,指标详解2.1 Counters计数器,以cpu的监控指标 node_cpu_seconds_total为例,这个指标就是计数器类型的,node_cpu_seconds_total这个指标就是某一核cpu某一个......
  • JAVA的第一个项目---品牌增删改查的案例
    这几周通过对javaweb的持续学习,终于做出了第一个项目界面比较简单,如下:通过超链接来查询表单的所有内容其下有新增,修改和删除三个按钮新增页面,点击提交增加数据修改页面用到了和新增一样的界面,通过id回显显示选中的品牌删除键进行删除直接回到查询表单界面项目创建分为......
  • 采集电力 IEC104 转 profinet IO 项目案例
    目录1 案例说明 12 VFBOX网关工作原理 13 准备工作 24 配置VFBOX网关采集IEC104设备数据 25 用PROFINETIO协议转发数据 46 获取104设备的数据地址 67 案例总结 81 案例说明设置网关采集IEC104设备数据把采集的数据转成profinetIO协议转发给其他系统。2 VFBOX网关工......
  • 《保卫萝卜》客户端缺失pthreadvce2.dll 文件?详解《保卫萝卜》Luobo.exe 加载 pthread
    在享受《保卫萝卜》这款趣味横生的塔防游戏时,部分玩家可能会遇到游戏无法启动的问题,屏幕上弹出错误提示:“由于找不到pthreadvce2.dll,无法继续执行代码。”这一错误通常意味着你的电脑系统中缺失了pthreadvce2.dll这个关键的动态链接库(DLL)文件。别担心,本文将为你提供详细的修......
  • 如何修复aurnianimation.dll文件缺失导致的古剑奇谭启动失败?详解《古剑奇谭》客户端缺
    针对《古剑奇谭》客户端因缺少 aurnianimation.dll 文件而导致的启动失败问题,以下是一系列详细的修复步骤,旨在帮助玩家恢复游戏的正常运行。一、检查回收站与备份检查回收站:打开计算机的回收站,搜索 aurnianimation.dll 文件。如果找到该文件,右键点击并选择“还原”,W......
  • LLaVA-1.5:强大的多模态大模型(包含论文代码详解)
    1.概述LLaVA是一个由威斯康星大学麦迪逊分校、微软研究院和哥伦比亚大学的研究人员开发的大型语言和视觉助手。它是一个端到端训练的大型多模态模型,结合了视觉编码器和语言模型,用于通用的视觉和语言理解。 微软研究院、威斯康星大学的研究人员在LLaVA基础之上,继续开源了LLa......