Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
445 views
in Technique[技术] by (71.8m points)

asp.net mvc 4 - DotNetOpenAuth 4.3 and Google - OpenID 2.0 + OAuth 1.0 deprecated

If you want to cut to the chase, the question is: what is the best/official way to use DotNetOpenAuth with Google in asp.net mvc 5?

About a year ago, I used OAuth (DotNetOpenAuth oAuth and OpenID) pretty much as it came out of the box for asp.net MVC 4 (as it is in the sample project). Since then I used it successfully for google, facebook, yahoo and microsoft. However, recently I have been having intermittent problems with users signing into google. I have tried upgrading to MVC 5 and DotNetOpenAuth 4.3, but I get the same.

When I looked at the google docs I found this:

Important: Google has deprecated its support for OAuth 1.0. If you are using OpenID 2.0 + OAuth 1.0, we recommend that you switch to Google+ Sign-In. Google+ Sign-In provides the OAuth 2.0 authentication mechanism with rich social features and access to additional Google desktop and mobile features. It supports all Google users and transparent migration. For details, see the Migration of Google authentication.

I could very well be mistaken, by I thought that out-of-the-box asp.net mvc 4 DotNetOpenAuth uses OpenID 2.0 (I use minimumRequiredOpenIdVersion="V20") + OAuth 1.0. I can see in the DotNetOpenAuth source that there is an OAuth 2.0 library under 'product', but I am not sure how to use this. Also, I am a bit nervous about Auth 2.0 as what I have read is not very complementary and it seems that it is easier to shoot oneself in the foot (might be unfounded, but it seems to be a recurring theme).

For Google+ I found these instructions which seem pretty straightforward, but that is almost a year ago, so I am wondering if this is still the best way to go. I also found this git repository implementing Google oauth2. Still, I would like to know whether this is still relevant as it is all from some time ago.

So, the question is - what is the best/official way to use DotNetOpenAuth with Google in asp.net mvc5? Hopefully I haven't missed anything obvious, in which case just a pointer to some links will be fine.

Update I found this question and this question which are related. I guess that I will go with the google auth2 from git unless I am told otherwise.

Resolution

I did the following: -

  • Followed the steps in the link provided by the accepted answer. It is this link.

It's important to keep using SSL after login and not drop back to HTTP, your login cookie is just as secret as your username and password…redirecting back to HTTP after you’re logged in won’t make the current request or future requests much faster.

  • Got the latest DotNetOpenAuth.GoogleOAuth2 on Nuget.

  • I looked at the recommendation from this msdn blog (by the same author) about how to best to secure the site. Basically, the recommendation is to add the following which will force all pages to HTTPS:

    filters.Add( new System.Web.Mvc.RequireHttpsAttribute() );

Ultimately what this means is that the whole site is HTTPS. Since making those changes, the site has been running fine.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

This is how you use DotnetOpenAuth with Google/OAuth2.

First, reference the DotnetOpenAuth.Ultimate package from Nuget.

Then create a provider class and the profile model class

public class GoogleClient : WebServerClient
{
    private static readonly AuthorizationServerDescription GoogleDescription = 
        new AuthorizationServerDescription
    {
        TokenEndpoint = new Uri( "https://accounts.google.com/o/oauth2/token" ),
        AuthorizationEndpoint = new Uri( "https://accounts.google.com/o/oauth2/auth" ),
        ProtocolVersion = ProtocolVersion.V20
    };

    public const string ProfileEndpoint = "https://www.googleapis.com/oauth2/v1/userinfo";

    public const string ProfileScope = "https://www.googleapis.com/auth/userinfo.profile";
    public const string EmailScope = "https://www.googleapis.com/auth/userinfo.email";

    public GoogleClient()
        : base( GoogleDescription )
    {
    }
}

public class GoogleProfileAPI
{
    public string email { get; set; }

    private static DataContractJsonSerializer jsonSerializer = 
        new DataContractJsonSerializer( typeof( GoogleProfileAPI ) );

    public static GoogleProfileAPI Deserialize( Stream jsonStream )
    {
        try
        {
            if ( jsonStream == null )
            {
                throw new ArgumentNullException( "jsonStream" );
            }

            return (GoogleProfileAPI)jsonSerializer.ReadObject( jsonStream );
        }
        catch ( Exception ex )
        {
            return new GoogleProfileAPI();
        }
    }
}

Then, in your login page (login controller) have this code:

    private static readonly GoogleClient googleClient = new GoogleClient
    {
        ClientIdentifier = "client_id",
        ClientCredentialApplicator = ClientCredentialApplicator.PostParameter( "client_secret" )
    };

        // Page_Load of login page if WebForms
        // Login action of the Account controller if MVC 

        IAuthorizationState authorization = googleClient.ProcessUserAuthorization();
        if ( authorization == null )
        {
            // Kick off authorization request
            // Google will redirect back here
            Uri uri = new Uri( "http://your.application.address/login" );
            googleClient.RequestUserAuthorization( returnTo: uri, 
                scope: new[] { GoogleClient.ProfileScope, GoogleClient.EmailScope } );
        }
        else
        {
            // authorization. we have the token and 
            // we just go to profile APIs to get email (and possibly other data)
            var request =
                WebRequest.Create(
                    string.Format( "{0}?access_token={1}", 
                    GoogleClient.ProfileEndpoint, 
                    Uri.EscapeDataString( authorization.AccessToken ) ) );
            using ( var response = request.GetResponse() )
            {
                using ( var responseStream = response.GetResponseStream() )
                {
                    var profile = GoogleProfileAPI.Deserialize( responseStream );
                    if ( profile != null &&
                        !string.IsNullOrEmpty( profile.email ) )
                        FormsAuthentication.RedirectFromLoginPage( profile.email, false );
                }
            }
        }

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...