Retrofit学习教程(4)-OAuth on Android
来源:互联网 发布:知乎 怪异故事和acfun 编辑:程序博客网 时间:2024/06/03 19:21
写在前面: 本文是我看到Retrofit官方推荐的一个Retrofit技术文档,感觉收益匪浅,特此想把文档翻译一下,大家一起学习。
原文地址:https://futurestud.io/tutorials/retrofit-getting-started-and-android-client
本文不会深入探讨OAuth本身。他只会展示基础的原则和必要的信息来帮助理解验证流程。
OAuth基础
OAuth是一个基于token的验证方法,它通过提供一个访问token来为用户和api进行交互。OAuth通过几个步骤和请求来获得你的访问token。
1.在api上注册一个你想要开发的App。使用你想要去开发的开发者网站的公共api。
2.在你的app中存储客户端id和客户端密钥。
3.请求从你的app中访问用户数据。
4.使用验证代码来获得访问token。
5.使用访问token和api进行交互。
注册你的App
首先,你必须为你想要开发的服务/api注册App。一旦你登入你的应用,你将会获得客户端id和客户端密匙。这两个值都将用来验证你的app。
创建工程
我们假设你已经有了一个工程,如果你没有,那么就去创建一个。当你做好之后,移至下一节,准备coding。
集成 OAuth
因为我们在上几章中,使用了ServiceGenerator,那么接下来我们依旧以此为基础进行拓展,增加一个方法来处理OAuth访问Token。下面的代码块显示所要的方法。这不意味着你应该删除先前为基础验证所创建的方法,因为你也需要他们。
public class ServiceGenerator { public static final String API_BASE_URL = "https://your.api-base.url"; private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder(); private static Retrofit.Builder builder = new Retrofit.Builder() .baseUrl(API_BASE_URL) .addConverterFactory(GsonConverterFactory.create()); public static <S> S createService(Class<S> serviceClass) { return createService(serviceClass, null); } public static <S> S createService(Class<S> serviceClass, String username, String password) { // we shortened this part, because it’s covered in // the previous post on basic authentication with Retrofit } public static <S> S createService(Class<S> serviceClass, AccessToken token) { if (token != null) { httpClient.addInterceptor(new Interceptor() { @Override public Response intercept(Interceptor.Chain chain) throws IOException { Request original = chain.request(); Request.Builder requestBuilder = original.newBuilder() .header("Accept", "application/json") .header("Authorization", token.getTokenType() + " " + token.getAccessToken()) .method(original.method(), original.body()); Request request = requestBuilder.build(); return chain.proceed(request); } }); } OkHttpClient client = httpClient.build(); Retrofit retrofit = builder.client(client).build(); return retrofit.create(serviceClass); }}
我们使用RequestInterceptor来设置HTTP请求头部的Authorization区域。这个区域包含两个部分:首先,OAuth请求的token类型,其次,访问token。
如你所见,这个方法请求一个AccessToken作为第三个参数,这个类如下所示:
public class AccessToken { private String accessToken; private String tokenType; public String getAccessToken() { return accessToken; } public String getTokenType() { // OAuth requires uppercase Authorization HTTP header value for token type if ( ! Character.isUpperCase(tokenType.charAt(0))) { tokenType = Character .toString(tokenType.charAt(0)) .toUpperCase() + tokenType.substring(1); } return tokenType; }}
AccessToken类包含两个区域:accessToken和tokenType。因为OAuth API实现需要大写的token类型,我们首先检测类型。万一它不合适,我们将更新类型。例如,你的API返回bearer类型,那么任何这个类型的请求都会导致要么401无法验证,要么403拒绝,要么400请求失败。
当设置正确时,HTTP头部会如下例子所示。
Authorization: Bearer 12345
在你的App中集成OAuth
首先我们我们创建一个叫做LoginActivity的新Activity。你可以使用一个只有一个button的简单的view。下面是activity的代码。
public class LoginActivity extends Activity { // you should either define client id and secret as constants or in string resources private final String clientId = "your-client-id"; private final String clientSecret = "your-client-secret"; private final String redirectUri = "your://redirecturi"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); Button loginButton (Button) findViewById(R.id.loginbutton); loginButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent( Intent.ACTION_VIEW, Uri.parse(ServiceGenerator.API_BASE_URL + "/login" + "?client_id=" + clientId + "&redirect_uri=" + redirectUri)); startActivity(intent); } }); }}
你必须协调clientID,clientSecret,redirectUri的类属性值。同时也要保证url的登入不能是有/login的,不然,则将这部分更新至正确的部分。接下来,在oncreate方法中为登入按钮设置一个点击监听事件。一旦点击事件被触发,它就会显示URI所指向的webview。重要的一点是:在这个请求中,你必须提供你的client id和cilent 密匙。因为API需要这两个参数来对你的app进行其他的操作和处理。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Login" android:id="@+id/loginbutton" android:gravity="center_vertical|center_horizontal" /></RelativeLayout>
创建一个intent删选器,它能帮助你删选你想要的响应。
<activity android:name="com.futurestudio.oauthexample.LoginActivity" android:label="@string/app_name" android:configChanges="keyboard|orientation|screenSize"> <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:host="redirecturi" android:scheme="your" /> </intent-filter></activity>
抓取验证的代码
@Overrideprotected void onResume() { super.onResume(); // the intent filter defined in AndroidManifest will handle the return from ACTION_VIEW intent Uri uri = getIntent().getData(); if (uri != null && uri.toString().startsWith(redirectUri)) { // use the parameter your API exposes for the code (mostly it's "code") String code = uri.getQueryParameter("code"); if (code != null) { // get access token // we'll do that in a minute } else if (uri.getQueryParameter("error") != null) { // show an error message here } }}
你的app在android的生命周期的onResume方法中进行操作,我们在这里使用了getIntent().getData()方法来检索intet的响应。
现在我们不想运行任何指针和检测值。接下来,我们从查询参数里组装处验证代码。设想一下,点击allow时,响应url如下所示。
your://redirecturi?code=1234
拒绝访问如下所示:
your://redirecturi?error=message
获得你的访问token
接下来,我们将通过传递client id,client secrest和验证代码给API来请求访问token。我们在上文的基础验证中的LoginService的基础上进行扩展,创建一个叫做getAccessToken的方法。
public interface LoginService { @FormUrlEncoded @POST("/token") Call<AccessToken> getAccessToken( @Field("code") String code, @Field("grant_type") String grantType);}
@Overrideprotected void onResume() { super.onResume(); // the intent filter defined in AndroidManifest will handle the return from ACTION_VIEW intent Uri uri = getIntent().getData(); if (uri != null && uri.toString().startsWith(redirectUri)) { // use the parameter your API exposes for the code (mostly it's "code") String code = uri.getQueryParameter("code"); if (code != null) { // get access token LoginService loginService = ServiceGenerator.createService(LoginService.class, clientId, clientSecret); Call<AccessToken> call = loginService.getAccessToken(code, "authorization_code"); AccessToken accessToken = call.execute().body(); } else if (uri.getQueryParameter("error") != null) { // show an error message here } }}
你做完之后,你可能必须为你请求的api调整许可类型。这个需求类型是通过getAccessToken的方法的第二个参数进行传递的。
- Retrofit学习教程(4)-OAuth on Android
- Retrofit学习教程(1)-创建一个Android客户端
- Retrofit学习教程(2)-Android基础验证
- Retrofit学习教程(3)-Token验证
- Android Retrofit使用教程(一)
- Android框架学习之Retrofit(一)
- Android学习之网络请求(retrofit)
- OAuth学习(一)
- Retrofit学习教程(4)-Multiple Query Parameters of Same Name
- Android Retrofit 2.0(二)使用教程OkHttp3 + Gson + RxJava
- Android框架学习之Retrofit(三)retrofit和okhttp的区别
- OAuth 2.0系列教程(一)引言
- OAuth 2.0系列教程(二) 综述
- OAuth 2.0系列教程(三) 角色
- OAuth 2.0系列教程(五) 授权
- OAuth 2.0系列教程(六) 端点
- OAuth 2.0系列教程(一)引言
- OAuth 2.0系列教程(二) 综述
- WebApp开发之Cordova安装教程
- spring 启动打印所有beans
- c# 操作excel生成pdf
- Elasticsearch 在Windows下的安装
- python之socket编程
- Retrofit学习教程(4)-OAuth on Android
- 用mysql的十大理由
- oracle shutdown到nomount
- http 和 https 总结
- 使用 Tkprof 分析 ORACLE 跟踪文件
- 北大青鸟怎么样???是骗子吗??
- 常规容器下SpringBootServletInitializer如何实现web.xml作用解析
- Sink a DotCom
- OpenCV学习常用网址