Google OAuth2 on Windows Phone

原文地址: http://www.codeproject.com/Articles/321291/Google-OAuth2-on-Windows-Phone

 

介绍下OAuth2.0

 

OAuth2.0是从2006年开始设计OAuth协议的下一个版本,OAuth2.0同时提供Web,桌面和移动应用程序的支持,并较1.0相比整个授权验证流程更简单更安全。也是新浪微博开放平台未来最主要的用户身份验证和授权方式。现在百度开放平台腾讯开放平台等大部分的开放平台都是使用的OAuth 2.0协议作为支撑。   

 

OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),

而无需将用户名和密码提供给第三方应用。

Windows Phone 7中使用Google API 和 OAuth2

 

介绍                                                 

Google公开了一系列丰富的API 允许应用程序和它们的应用、服务、数据交互。 Google 支持多种认证和授权机制他们建议使用 OAuth2 ,

因此我就在考虑如何在Windows Phone 7中使用这个。

如果你和我一样也在使用Google Services ,你就要去看下OAuth2重温下相关示例,希望你能找到一些有用的或者感兴趣的部分移植到你的应用程序中。

这里面有大量的关于OAuth2文档和使用示例。甚至有一个 Google写的.NET 

开发过程有一点细微的差别,我们开发的应用程序需要处理各种不同的使用情况(环境)。它们已经封装好的库中我没有发现任何详细的解释或者用这种方式去创建它们.

  1. OAuth2对于一个已经安装的应用程序是一个多步处理过程。应用程序不用从用户抓取用户名和密码而是显示一个内嵌的网页进行身份验证。App登陆成功之后会收到一个用于交换access tokenCode.

  2. 身份验证的过程是同步的但是通信交互过程是异步的。

  3. access token 会有一个期限,到期时,它可以使用户无需重新验证,但这需要应用程序请求google重新刷新 .

  4. access token 可以序列化,使应用程序的新实例不必重新验证。

  5. 在应用程序环境以外的任何时候用户都可以随时撤销访问google服务的许可。

首先,如果你从来都没有使用过 Google API这就需要你好好的了解下它们的Services 是如何工作的。 对于 OAuth2 installed application implementation

也需要有一个基本的了解。

如果你创建的 App 需要使用一个google service 你必须用他们的 API Console 进行注册.

从那里获取 ClientId and secret 

附加代码要用到:

1. RestSharp

2. JSON.NET

3. MVVM Light

 

上面的这些你可以通过 Nuget 包获取。这篇文章写的时候用的是最新版本的RestSharp (102.6) 

最新版本的JSON.NET (4.0.7)  好像木有用。可能你需要确保获取的时  JSON.NET (4.05版本的

注意:

 

为了能够运行这个demo 你必须在google code上注册 然后得到一个Client ID Secret key AuthenticationViewModel构造函数中输入

 

            #warning PUT YOUR APP SPECIFIC STUFF HERE
            _process =  new AuthenticationProcess()
            {
                ClientId =  " YOUR APP CLIENT ID ",
                Secret =  " YOUR APP SECRET ",

                 //  this specifies which Google APIs your app 
                
//  intends to use and needs permission for
                Scope =  " https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile "
            };

 

OAuth2 序列图                                      

基本的OAuth2序列是一系列的 在用户、应用程序、Google 之间请求/响应 

 

Google OAuth2 on Windows Phone

 

在登录和身份验证的时候你并没有和应用程序直接交互。其实用户是和Google直接进行交互的但是你的应用程序为了进行下一步处理需要知道交互的结果(登录是否成功)

在这个使用MVVM模式的应用程序中,身份验证的逻辑处理类是 AuthenticationViewModel类。

google 的通信来回在AuthenticationProcess类。

 

有一件事情你可能注意到了 在登陆过程中(auth View Model 以外)没有发现任何其他的代码。 在 auth view model 唯一做的事情是必须确保是异步获取登陆代码.

只有它能够进行应用程序的的身份验证,或者至少它能够调用回调。

 

这是一个运用了MVVM模型的例子。它附带了一个ViewModelLocator一个MainPage 页和一个 MainViewModelMainPage页是应用程序开始导航的页面。并且是一个叫做持有用户Google 个人信息的Profile的 MainViewModel 中属性对应的 UI banding的部分。

UI 绑定从AuthenticationViewModel检索 access token 文件数据的MainViewModel 中的属性.  

在这个示例中auth view model 传递给 MainViewModel的构造函数和它的 _authProvider 成员。

 

public Profile Profile
{
     get
    {
         if(_profile ==  null)
            _authProvider.GetAccessCode(s => LoadProfile(s));

         return _profile;
    }
     set
    {
         if (_profile != value)
        {
            _profile = value;
            RaisePropertyChanged( " Profile ");
        }
    }
}
 

 

调用AuthenticationViewModel , GetAccessCode 方法封装了认证的逻辑、授权、刷新。

 

private Queue<Action< string>> _queuedRequests =  new Queue<Action< string>>();
public  void GetAccessCode(Action< string> callback)
{
     lock (_sync)
    {
         if (_isAuthenticating)
        {
            _queuedRequests.Enqueue(callback);
        }
         else  if (HasAuthenticated)
        {
             if (!_process.AuthResult.IsExpired)
            {
                callback(_process.AuthResult.access_token);
            }
             else
            {
                _isAuthenticating =  true;
                _queuedRequests.Enqueue(callback);
                _process.RefreshAccessToken();
            }
        }
         else
        {
            _isAuthenticating =  true;
            _queuedRequests.Enqueue(callback);

            ((PhoneApplicationFrame)App.Current.RootVisual).Navigate( new Uri( " /AuthenticationPage.xaml ", UriKind.Relative));
            AuthUri = _process.AuthUri;
        }
    }
}
 

 

这个方法进行了以下几个事情。

1.如果一个认证的过程已经在进行,队列回调并且返回。

2.如果用户已经进行了身份验证并且 access token 是有效的,只需调用回调。

3.如果用户已经进行了身份验证但是 access token 已经过期了,队列回调并且刷新 token

4.如果用户身份验证失败,队列回调并且导航到身份验证页面。

下面这一块是第一次运行应用程序,用户将导航到身份验证页面 WebBrower 控件显示的是在auth view model 的AuthUri 属性指定的url页。

AuthUri是用户登录google 身份验证的 uri地址,例如下面的样子:

https://accounts.google.com/o/oauth2/auth?response_type=code&redirect_uri=http://localhost&scope=https://www.googleapis.com/auth/userinfo.email%20https://www.googleapis.com/auth/userinfo.profile&client_id=YYYY

Google OAuth2 on Windows Phone

 

Google验证时,它们将被要求授权你的应用程序在上面的Uri 中分别定义的client_id 和 范围参数

来访问一个已定义的系列API

Google OAuth2 on Windows Phone

 

当用户按下“Allow access” Google 将浏览器重定向到我们起始地址的redirect_uri .

AutenticationPage 页的后台代码看到网页浏览器将主机指定到原始地址的参数 redirect_uri .

我们知道Google 正在回传我们一个 access code 用于我们能够交换的 access token .

这个access code 是我们的重定向地址参数的一部分.

我们实际上不能导航到这个 redirect_uri 而是将它作为哨兵的作用 来让我们知道身份验证成功。

 

    private  void webBrowser1_Navigating( object sender, NavigatingEventArgs e)
    {
         if (e.Uri.Host.Equals( " localhost "))  //  in our case we used localhost as the redirect_uri
        {
            webBrowser1.Visibility = Visibility.Collapsed;
            e.Cancel =  true;
             int pos = e.Uri.Query.IndexOf( " = ");

             //  setting this ui element text will bind it back to the view model
            codeBlock.Text = pos > - 1 ? e.Uri.Query.Substring(pos +  1) :  null;
        }
    }
 

 

code 发送到了 auth view model (这种情况下是因为我们有一个隐藏的textBlock进行了双向绑定)

View model 用它来交换一个 access toke

 

    private  string _code;
     public  string Code
    {
         get
        {
             return _code;
        }
         set
        {
            _code = value;
            _process.ExchangeCodeForToken(Code);
        }
    }
 
    ...

     class AuthenticationProcess
    {
         public  void ExchangeCodeForToken( string code)
        {
             if ( string.IsNullOrEmpty(code))
            {
                OnAuthenticationFailed();
            }
             else
            {
                 var request =  new RestRequest( this.TokenEndPoint, Method.POST);
                request.AddParameter( " code ", code);
                request.AddParameter( " client_id "this.ClientId);
                request.AddParameter( " client_secret "this.Secret);
                request.AddParameter( " redirect_uri "" http://localhost ");
                request.AddParameter( " grant_type "" authorization_code ");

                client.ExecuteAsync<AuthResult>(request, GetAccessToken);
            }
        }

         void GetAccessToken(IRestResponse<AuthResult> response)
        {
             if (response ==  null || response.StatusCode != HttpStatusCode.OK
                || response.Data ==  null ||  string.IsNullOrEmpty(response.Data.access_token))
            {
                OnAuthenticationFailed();
            }
             else
            {
                Debug.Assert(response.Data !=  null);
                AuthResult = response.Data;
                OnAuthenticated();
            }
        }

    }
 

 

AuthenticationProcess 类传递信号给 auth view model 身份验证成功。

View model 调用队列回调,然后整个过程结束。

 

    void _process_Authenticated( object sender, EventArgs e)
    {
        _isAuthenticating =  false;

         while (_queuedRequests.Count >  0)
            _queuedRequests.Dequeue()(_process.AuthResult.access_token);

        ViewModelLocator.SaveSetting( " auth ", _process.AuthResult);        

        RaisePropertyChanged( " HasAuthenticated ");
    }
 

 

回调完成后,回到MainViewModel一个有效的 access token 现在是可以调用的现在我们移到我们正在要做事情:

通过传递 access token 去调用google 的 api 获取数据。

 

    private  void LoadProfile( string access_token)
    {
        Debug.WriteLine( " loading profile ");

        RestClient client =  new RestClient( " https://www.googleapis.com ");
        client.Authenticator =  new OAuth2AuthorizationRequestHeaderAuthenticator(access_token);
         var request =  new RestRequest( " /oauth2/v1/userinfo ", Method.GET);
        client.ExecuteAsync<Profile>(request, ProfileLoaded);
    }

     private  void ProfileLoaded(IRestResponse<Profile> response)
    {
        Profile = response.Data;
    }
 

 Google OAuth2 on Windows Phone

 

access token需要刷新时,无须UI,只要一个相似的队列。

 

从安全的角度我们可以看到 OAuth2的优势。在整个过程只有用户和Google在交互

没有密码存储在客户端。也从来不需要应用程序传递一个密码给Google的 API.

在请求用户凭证和包括它们的每次调用可以使复杂事情简单化。

 

注:https://code.google.com/apis/console/ 、 https://code.google.com/   ...  可能无法打开

 

本文源码下载:

 

你可能感兴趣的:(windows phone)