You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native基于校园API实现OAuth2授权码流程及获取code的方法咨询

React Native 实现OAuth2授权码流程(含回调code获取与token兑换)

一、前期配置

先和学校OAuth服务确认以下核心参数:

  • client_id:你的应用在学校OAuth系统的专属标识
  • 授权端点URL(例如 https://school-domain/oauth/authorize)
  • token兑换端点URL(例如 https://school-domain/oauth/token)
  • 已注册的redirect_uri:格式通常为yourapp://oauth-callback(自定义URL Scheme,必须和学校OAuth配置完全一致)

接着在React Native项目中配置URL Scheme:

  • iOS:打开Info.plist,添加CFBundleURLTypes数组:
    <key>CFBundleURLTypes</key>
    <array>
      <dict>
        <key>CFBundleURLSchemes</key>
        <array>
          <string>yourapp</string>
        </array>
      </dict>
    </array>
    
  • Android:打开AndroidManifest.xml,在主<activity>标签内添加intent-filter:
    <intent-filter>
      <action android:name="android.intent.action.VIEW" />
      <category android:name="android.intent.category.DEFAULT" />
      <category android:name="android.intent.category.BROWSABLE" />
      <data android:scheme="yourapp" />
    </intent-filter>
    

二、触发授权跳转

在模态框的授权按钮点击事件中,构造完整授权URL并唤起浏览器:

import { Linking } from 'react-native';

const handleAuthButtonPress = () => {
  // 生成随机state值,用于后续防CSRF验证
  const randomState = Math.random().toString(36).substring(2, 15);
  // 保存state到本地(比如AsyncStorage)
  await AsyncStorage.setItem('oauthState', randomState);

  const authUrl = `${schoolAuthEndpoint}?client_id=${clientId}&redirect_uri=${redirectUri}&response_type=code&scope=your-required-scopes&state=${randomState}`;
  Linking.openURL(authUrl);
};

三、捕获回调并提取授权码code

在App组件中通过Linking监听URL跳转事件,解析回调URL中的code参数:

import { Linking, useEffect } from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';

useEffect(() => {
  const handleRedirect = async (event) => {
    const url = event.url;
    // 验证是否为目标回调URL
    if (url.startsWith(redirectUri)) {
      const queryParams = new URLSearchParams(url.split('?')[1]);
      const code = queryParams.get('code');
      const returnedState = queryParams.get('state');
      const savedState = await AsyncStorage.getItem('oauthState');

      // 验证state一致性,防止CSRF攻击
      if (returnedState === savedState) {
        // 拿到code后调用token兑换方法
        await exchangeCodeForToken(code);
      } else {
        console.error('State验证失败,可能存在CSRF风险');
      }
    }
  };

  // 注册URL监听
  Linking.addEventListener('url', handleRedirect);
  // 组件卸载时移除监听
  return () => Linking.removeEventListener('url', handleRedirect);
}, []);

四、用code兑换access token

构造POST请求到学校的token端点,完成token兑换:

const exchangeCodeForToken = async (code) => {
  try {
    const response = await fetch(schoolTokenEndpoint, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
      },
      body: new URLSearchParams({
        grant_type: 'authorization_code',
        code: code,
        redirect_uri: redirectUri,
        client_id: clientId,
        // 若学校要求client_secret,注意:移动应用不要硬编码该值!推荐改用PKCE流程
        // client_secret: clientSecret,
        // 若使用PKCE,需在此添加code_verifier参数
      }),
    });

    const data = await response.json();
    if (data.access_token) {
      // 将token存入安全存储(推荐用react-native-keychain替代AsyncStorage)
      await AsyncStorage.setItem('accessToken', data.access_token);
      // 后续即可用该token调用学校API
    } else {
      console.error('Token兑换失败:', data.error_description || data.error);
    }
  } catch (error) {
    console.error('请求出错:', error);
  }
};

核心注意事项

  • PKCE流程:移动应用属于公共客户端,无法安全存储client_secret,强烈建议使用PKCE扩展流程。生成code_challenge和code_verifier,授权时携带code_challenge与code_challenge_method=S256,兑换token时携带code_verifier,避免code被拦截盗用。
  • 错误处理:需覆盖授权被拒绝、code过期、token兑换失败等异常场景,给用户明确提示。
  • token存储:不要将access token存在全局变量,优先使用安全存储库(如react-native-keychain)。

内容的提问来源于stack exchange,提问作者kostis14

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 03:24:22