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

Android 7.1.1(API 25)中基于Retrofit2的OAuth2认证问题咨询

在Android 7.1.1(API25)用Retrofit2实现OAuth2认证流程

我来分享下匹配你需求的完整实现方案——在指定Android版本下,通过Activity的onCreate发起OAuth授权请求,onResume捕获授权码,再用Retrofit2完成Token交换的全流程:

一、先确认Manifest的意图过滤器配置

这一步是浏览器能跳转回你App的核心,一定要配置正确,还要注意Activity的启动模式:

<activity
    android:name=".AuthActivity"
    android:launchMode="singleTask"> <!-- 关键:避免重复创建实例,确保onResume能拿到回调数据 -->
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <!-- 替换成你在OAuth服务器注册的回调URL的scheme和host -->
        <data
            android:scheme="your-custom-scheme"
            android:host="oauth-callback" />
    </intent-filter>
</activity>

二、AuthActivity核心逻辑实现

1. onCreate中发起授权请求

在启动页或者认证Activity的onCreate里,构造OAuth授权URL并唤起浏览器:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_auth);

    // 构造授权URL,替换成你的实际参数
    String authRequestUrl = "https://your-oauth-server.com/authorize" +
            "?client_id=your-client-id" +
            "&redirect_uri=your-custom-scheme://oauth-callback" +
            "&response_type=code" +
            "&scope=user_info read_data";

    // 启动浏览器打开授权页面
    Intent authIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(authRequestUrl));
    startActivity(authIntent);
}

2. onResume中捕获授权码

用户在浏览器完成授权后,会跳回你的AuthActivity,此时在onResume里解析回调URL中的授权码:

@Override
protected void onResume() {
    super.onResume();

    Uri callbackData = getIntent().getData();
    if (callbackData != null) {
        // 提取授权码
        String authCode = callbackData.getQueryParameter("code");
        if (authCode != null) {
            // 拿到授权码后,立刻调用Retrofit2换取Access Token
            exchangeAuthCodeForToken(authCode);
        } else {
            // 处理用户拒绝授权或其他错误
            String errorMsg = callbackData.getQueryParameter("error_description");
            Toast.makeText(this, "授权失败:" + errorMsg, Toast.LENGTH_SHORT).show();
        }
        // 清除Intent数据,防止下次onResume重复解析
        setIntent(null);
    }
}

三、用Retrofit2实现Token交换

1. 定义Retrofit接口和实体类

先写接口描述OAuth的Token交换接口,以及响应实体:

// OAuth API接口
public interface OAuthService {
    @FormUrlEncoded
    @POST("oauth/token") // 替换成你的OAuth服务器Token接口路径
    Call<TokenResponse> fetchAccessToken(
            @Field("grant_type") String grantType,
            @Field("client_id") String clientId,
            @Field("client_secret") String clientSecret,
            @Field("code") String authCode,
            @Field("redirect_uri") String redirectUri
    );
}

// Token响应实体类,用Gson解析
public class TokenResponse {
    @SerializedName("access_token")
    public String accessToken;
    @SerializedName("token_type")
    public String tokenType;
    @SerializedName("expires_in")
    public long expiresIn;
    @SerializedName("refresh_token")
    public String refreshToken;
}

2. 实现Token交换方法

在AuthActivity里实现exchangeAuthCodeForToken方法,完成网络请求:

private void exchangeAuthCodeForToken(String authCode) {
    // 初始化Retrofit实例
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("https://your-oauth-server.com/") // 替换成服务器根路径
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    OAuthService oAuthService = retrofit.create(OAuthService.class);

    Call<TokenResponse> tokenCall = oAuthService.fetchAccessToken(
            "authorization_code",
            "your-client-id",
            "your-client-secret", // 注意:敏感信息不要硬编码,建议通过安全方式存储
            authCode,
            "your-custom-scheme://oauth-callback"
    );

    tokenCall.enqueue(new Callback<TokenResponse>() {
        @Override
        public void onResponse(Call<TokenResponse> call, Response<TokenResponse> response) {
            if (response.isSuccessful() && response.body() != null) {
                TokenResponse token = response.body();
                // 把Token保存到SharedPreferences或者其他安全存储
                saveTokenToStorage(token);
                // 授权完成,跳转到主页面并关闭当前页
                startActivity(new Intent(AuthActivity.this, MainActivity.class));
                finish();
            } else {
                Toast.makeText(AuthActivity.this, "Token换取失败", Toast.LENGTH_SHORT).show();
            }
        }

        @Override
        public void onFailure(Call<TokenResponse> call, Throwable t) {
            Toast.makeText(AuthActivity.this, "网络错误:" + t.getMessage(), Toast.LENGTH_SHORT).show();
        }
    });
}

四、几个关键注意点

  • 回调URL一致性:确保Manifest里配置的scheme/host,和OAuth服务器注册的回调URL完全一致,包括大小写、路径(如果有的话);
  • HTTP请求权限:API25如果访问的是HTTP服务器,需要在Manifest的<application>标签里添加android:usesCleartextTraffic="true",或者配置network security config;
  • 启动模式:必须设置singleTask,否则浏览器跳转回来会创建新的Activity实例,导致onResume拿不到正确的Intent数据;
  • 敏感信息防护:客户端密钥不要直接写在代码里,建议通过后端代理或者NDK加密存储,避免反编译泄露;
  • 错误处理:不要忽略error参数,用户拒绝授权、授权超时等情况都会返回错误信息,要友好提示用户。

内容的提问来源于stack exchange,提问作者F. Aydemir

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 04:31:07