如何使用刷新令牌更新访问令牌? [英] How to renew the access token using the refresh token?

查看:22
本文介绍了如何使用刷新令牌更新访问令牌?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我将 ASP.NET MVC 5OWIN 一起使用.

我做了很多研究,还没有找到如何使用刷新令牌更新访问令牌.

我的场景是:用户第一次访问我的应用程序时,他或她授予我读取从 API 返回的刷新令牌的帐户的访问权限.当用户回到我的应用程序时,我需要根据刷新令牌"刷新访问令牌.

谁能提供一些代码?

这是我迄今为止取得的成就:

Startup.Auth.cs:

 var googleOAuth2AuthenticationOptions = new GoogleOAuth2AuthenticationOptions{Caption = "Google+",ClientId = Parameters.Instance.Authentication.oAuth.GooglePlus.ClientId,ClientSecret = Parameters.Instance.Authentication.oAuth.GooglePlus.ClientSecret,CallbackPath = new PathString("/oauth-login-return"),提供者 = 新的 GoogleOAuth2AuthenticationProvider{OnAuthenticated = 异步上下文 =>{context.Identity.AddClaim(new Claim(ClaimTypes.Name, context.Identity.FindFirstValue(ClaimTypes.Name)));context.Identity.AddClaim(new Claim(ClaimTypes.Email, context.Identity.FindFirstValue(ClaimTypes.Email)));context.Identity.AddClaim(new Claim("picture", context.User.GetValue("picture").ToString()));context.Identity.AddClaim(new Claim("profile", context.User.GetValue("profile").ToString()));context.Identity.AddClaim(新声明(Parameters.Instance.Authentication.oAuth.GooglePlus.AccessTokenClaimType,context.AccessToken));}}};googleOAuth2AuthenticationOptions.Scope.Add("https://www.googleapis.com/auth/plus.login");googleOAuth2AuthenticationOptions.Scope.Add("https://www.googleapis.com/auth/userinfo.email");

身份验证控制器:

[HttpPost][允许匿名]公共 ActionResult ExternalLogin(string provider, string returnUrl){RedirectIfAuthenticated();return new ChallengeResult(provider, Url.Content("~/oauth-login-callback"));}[ActionName("oauth-login-back")]公共异步任务ExternalLoginCallback(string returnUrl){}//添加外部登录时用于 XSRF 保护private const string XsrfKey = "XsrfId";私有 IAuthenticationManager AuthenticationManager{得到{返回 HttpContext.GetOwinContext().Authentication;}}私有类 ChallengeResult : HttpUnauthorizedResult{公共挑战结果(字符串提供者,字符串 redirectUri):这个(提供者,redirectUri,空){}私人挑战结果(字符串提供者,字符串redirectUri,字符串userId){登录提供者 = 提供者;RedirectUri = redirectUri;用户 ID = 用户 ID;}私人字符串 LoginProvider { get;放;}私有字符串 RedirectUri { 获取;放;}私有字符串 UserId { 获取;放;}公共覆盖无效 ExecuteResult(ControllerContext 上下文){var properties = new AuthenticationProperties { RedirectUri = RedirectUri };如果(用户 ID != 空){properties.Dictionary[XsrfKey] = UserId;}context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider);}}

解决方案

这个问题根本不重复.我希望这能帮助其他人不要像我一样度过几天.

将近 4 天后,我发现了如何使用 OWIN 在 google api 中获取新的访问令牌.

我将发布解决方案,但首先,我必须说,帮助我开始获得有关我的错误的线索的是为 Katana 项目设置调试符号.请参阅此链接:

更具体地说这个答案:https://stackoverflow.com/a/24401189/833846

之后,我前往 Google Developers Console 并设置了 Google+ API

然后,瞧!成功了.

现在,使用刷新令牌获取新访问令牌的代码(我还没有找到任何使用 OWIN API 实现该目的的方法).

公共静态类TokenValidator{///<总结>///Obtém um novo access token na API do google.///</总结>///<param name="clientId"></param>///<param name="clientSecret"></param>///<param name="refreshToken"></param>///<returns></returns>public static GoogleRefreshTokenModel ValidateGoogleToken(string clientId, string clientSecret, string refreshToken){const string url = "https://accounts.google.com/o/oauth2/token";var parameters = new List>{new KeyValuePair("client_id", clientId),new KeyValuePair("client_secret", clientSecret),new KeyValuePair("grant_type", "refresh_token"),new KeyValuePair("refresh_token", refreshToken)};var content = GetContentAsync(url, "POST", parameters);var token = JsonConvert.DeserializeObject<GoogleRefreshTokenModel>(content);返回令牌;}私有静态字符串 GetContentAsync(string url,字符串方法 = "POST",IEnumerable>参数 = 空){返回方法==POST"?PostAsync(url, parameters) : GetAsync(url, parameters);}私有静态字符串 PostAsync(string url, IEnumerable> parameters = null){var uri = new uri(url);var request = WebRequest.Create(uri) as HttpWebRequest;request.Method = "POST";request.KeepAlive = true;request.ContentType = "application/x-www-form-urlencoded";var postParameters = GetPostParameters(参数);var bs = Encoding.UTF8.GetBytes(postParameters);使用 (var reqStream = request.GetRequestStream()){reqStream.Write(bs, 0, bs.Length);}使用 (var response = request.GetResponse()){var sr = new StreamReader(response.GetResponseStream());var jsonResponse = sr.ReadToEnd();sr.关闭();返回 jsonResponse;}}私有静态字符串 GetPostParameters(IEnumerable> parameters = null){var postParameters = string.Empty;foreach(参数中的var参数){postParameters += string.Format("&{0}={1}", parameter.Key,HttpUtility.HtmlEncode(parameter.Value));}postParameters = postParameters.Substring(1);返回帖子参数;}私有静态字符串 GetAsync(字符串 url, IEnumerable> parameters = null){网址+=?"+ GetQueryStringParameters(参数);var forIdsWebRequest = WebRequest.Create(url);使用 (var response = (HttpWebResponse)forIdsWebRequest.GetResponse()){使用 (var data = response.GetResponseStream())使用 (var reader = new StreamReader(data)){var jsonResponse = reader.ReadToEnd();返回 jsonResponse;}}}私有静态字符串 GetQueryStringParameters(IEnumerable> parameters = null){var queryStringParameters = string.Empty;foreach(参数中的var参数){queryStringParameters += string.Format("&{0}={1}", parameter.Key,HttpUtility.HtmlEncode(parameter.Value));}queryStringParameters = queryStringParameters.Substring(1);返回查询字符串参数;}}

重要事项 1: 要获得刷新令牌,您必须在ExecuteResult"方法中将access_type"设置为offline",这样:

properties.Dictionary["access_type"] = "offline";

重要事项 2: 获得刷新令牌后,您必须将其存储在某个安全来源中.Google API 不会向您发出新的刷新令牌,除非您在调用该行之前将approval_prompt"设置为force"(以相同的方法):

context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider);

我还建议您查看:

Google API 离线访问

Google OAUTH 2.0 Playground

Google API 发现检查

I am using ASP.NET MVC 5 with OWIN.

I have done a lot of research and haven't found how to renew the access token using the refresh token.

My scenario is: The first time the user accesses my app, he or she grants access to the account I read the refresh token returned from the API. When the users come back to my app, I need to refresh the access token based on the "Refresh Token".

Could anybody provide some code?

Here is what I've achieved till now:

Startup.Auth.cs:

    var googleOAuth2AuthenticationOptions = new GoogleOAuth2AuthenticationOptions
    {
        Caption = "Google+",
        ClientId = Parameters.Instance.Authentication.oAuth.GooglePlus.ClientId,
        ClientSecret = Parameters.Instance.Authentication.oAuth.GooglePlus.ClientSecret,
        CallbackPath = new PathString("/oauth-login-return"),
        Provider = new GoogleOAuth2AuthenticationProvider
        {
            OnAuthenticated = async context =>
            {
                context.Identity.AddClaim(new Claim(ClaimTypes.Name, context.Identity.FindFirstValue(ClaimTypes.Name)));
                context.Identity.AddClaim(new Claim(ClaimTypes.Email, context.Identity.FindFirstValue(ClaimTypes.Email)));
                context.Identity.AddClaim(new Claim("picture", context.User.GetValue("picture").ToString()));
                context.Identity.AddClaim(new Claim("profile", context.User.GetValue("profile").ToString()));
                context.Identity.AddClaim(
                    new Claim(Parameters.Instance.Authentication.oAuth.GooglePlus.AccessTokenClaimType,
                        context.AccessToken));
            }
        }
    };
    googleOAuth2AuthenticationOptions.Scope.Add("https://www.googleapis.com/auth/plus.login");
    googleOAuth2AuthenticationOptions.Scope.Add("https://www.googleapis.com/auth/userinfo.email");

AuthenticationController:

[HttpPost]
[AllowAnonymous]
public ActionResult ExternalLogin(string provider, string returnUrl)
{
    RedirectIfAuthenticated();

    return new ChallengeResult(provider, Url.Content("~/oauth-login-callback"));
}

[ActionName("oauth-login-back")]
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
}

// Used for XSRF protection when adding external logins
private const string XsrfKey = "XsrfId";

private IAuthenticationManager AuthenticationManager
{
    get
    {
        return HttpContext.GetOwinContext().Authentication;
    }
}

private class ChallengeResult : HttpUnauthorizedResult
{
    public ChallengeResult(string provider, string redirectUri)
        : this(provider, redirectUri, null)
    {
    }

    private ChallengeResult(string provider, string redirectUri, string userId)
    {
        LoginProvider = provider;
        RedirectUri = redirectUri;
        UserId = userId;
    }

    private string LoginProvider { get; set; }

    private string RedirectUri { get; set; }

    private string UserId { get; set; }

    public override void ExecuteResult(ControllerContext context)
    {
        var properties = new AuthenticationProperties { RedirectUri = RedirectUri };
        if (UserId != null)
        {
            properties.Dictionary[XsrfKey] = UserId;
        }
        context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider);
    }
}

解决方案

This question isn't duplicate AT ALL. I hope this help others not spending days like I have spent.

After almost 4 days I have found out how to get a fresh access token in the google api using OWIN.

I'm going to post the solution, but first, I MUST say that what helped me to start getting a clue about my error was setting up the Debug Symbols for the Katana project. See this link: http://www.symbolsource.org/Public/Home/VisualStudio

This image show how to configure Debug Symbols Servers.

And this one shows the Katana Debug Symbols being loaded.

After that, I found out that my problem was that Google API was returning 403: Forbidden

"Access Not Configured. Please use Google Developers Console to activate the API for your project"

Then, found on stack overflow this post: "Access Not Configured. Please use Google Developers Console to activate the API for your project."

more specifically this Answer: https://stackoverflow.com/a/24401189/833846

After that, I went to Google Developers Console and setup up Google+ API

And then, voillá! It worked.

Now, the code to get a fresh access token using the refresh token (I haven't found any way to accomplish that using the OWIN API).

public static class TokenValidator
{
    /// <summary>
    /// Obtém um novo access token na API do google.
    /// </summary>
    /// <param name="clientId"></param>
    /// <param name="clientSecret"></param>
    /// <param name="refreshToken"></param>
    /// <returns></returns>
    public static GoogleRefreshTokenModel ValidateGoogleToken(string clientId, string clientSecret, string refreshToken)
    {
        const string url = "https://accounts.google.com/o/oauth2/token";

        var parameters = new List<KeyValuePair<string, string>>
        {
            new KeyValuePair<string, string>("client_id", clientId),
            new KeyValuePair<string, string>("client_secret", clientSecret),
            new KeyValuePair<string, string>("grant_type", "refresh_token"),
            new KeyValuePair<string, string>("refresh_token", refreshToken)
        };

        var content = GetContentAsync(url, "POST",  parameters);

        var token = JsonConvert.DeserializeObject<GoogleRefreshTokenModel>(content);

        return token;
    }

    private static string GetContentAsync(string url, 
        string method = "POST",
        IEnumerable<KeyValuePair<string, string>> parameters = null)
    {
        return method == "POST" ? PostAsync(url, parameters) : GetAsync(url, parameters);
    }

    private static string PostAsync(string url, IEnumerable<KeyValuePair<string, string>> parameters = null)
    {
        var uri = new Uri(url);

        var request = WebRequest.Create(uri) as HttpWebRequest;
        request.Method = "POST";
        request.KeepAlive = true;
        request.ContentType = "application/x-www-form-urlencoded";

        var postParameters = GetPostParameters(parameters);

        var bs = Encoding.UTF8.GetBytes(postParameters);
        using (var reqStream = request.GetRequestStream())
        {
            reqStream.Write(bs, 0, bs.Length);
        }

        using (var response = request.GetResponse())
        {
            var sr = new StreamReader(response.GetResponseStream());
            var jsonResponse = sr.ReadToEnd();
            sr.Close();

            return jsonResponse;
        }
    }

    private static string GetPostParameters(IEnumerable<KeyValuePair<string, string>> parameters = null)
    {
        var postParameters = string.Empty;
        foreach (var parameter in parameters)
        {
            postParameters += string.Format("&{0}={1}", parameter.Key,
                HttpUtility.HtmlEncode(parameter.Value));
        }
        postParameters = postParameters.Substring(1);

        return postParameters;
    }

    private static string GetAsync(string url, IEnumerable<KeyValuePair<string, string>> parameters = null)
    {
        url += "?" + GetQueryStringParameters(parameters);

        var forIdsWebRequest = WebRequest.Create(url);
        using (var response = (HttpWebResponse)forIdsWebRequest.GetResponse())
        {
            using (var data = response.GetResponseStream())
            using (var reader = new StreamReader(data))
            {
                var jsonResponse = reader.ReadToEnd();

                return jsonResponse;
            }
        }
    }

    private static string GetQueryStringParameters(IEnumerable<KeyValuePair<string, string>> parameters = null)
    {
        var queryStringParameters = string.Empty;
        foreach (var parameter in parameters)
        {
            queryStringParameters += string.Format("&{0}={1}", parameter.Key,
                HttpUtility.HtmlEncode(parameter.Value));
        }
        queryStringParameters = queryStringParameters.Substring(1);

        return queryStringParameters;
    }
}

IMPORTANT 1: To get a refresh token you must set the "access_type" to "offline" in the "ExecuteResult" method, this way:

properties.Dictionary["access_type"] = "offline";

IMPORTANT 2: Once you get your refresh token, you must store it and in some secure source. Google API won't issue you a new refresh token, unless you set "approval_prompt" to "force" before you call the line (in the same method):

context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider);

I also recommend taking a look at:

Google API Offline Access

Google OAUTH 2.0 Playground

Google API Discovery Check

这篇关于如何使用刷新令牌更新访问令牌?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆