Как обновить токен доступа с помощью токена обновления?

Я использую ASP.NET MVC 5 с OWIN.

Я провел много исследований и не нашел, как обновить токен доступа с помощью токена обновления.

Мой сценарий: в первый раз, когда пользователь обращается к моему приложению, он или она предоставляет доступ к учетной записи, которую я читаю токен обновления, возвращаемый 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"),
        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);
    }
}

Ответ 1

Этот вопрос не дублируется AT ALL. Я надеюсь, что это поможет другим не проводить такие дни, как я провел.

Спустя почти 4 дня я узнал, как получить новый токен доступа в google api, используя OWIN.

Я собираюсь опубликовать это решение, но во-первых, я ДОЛЖЕН сказать, что то, что помогло мне разобраться в моей ошибке, заключалось в создании символов Debug для проекта Katana. См. Эту ссылку: http://www.symbolsource.org/Public/Home/VisualStudio

На этом изображении показано, как настроить серверы Debug Symbols. enter image description here

И это показывает загруженные символы Katana Debug. enter image description here

После этого я узнал, что моя проблема в том, что Google API возвращался 403: Запрещено

"Доступ не настроен. Используйте Google Developers Console для активации API для вашего проекта"

Затем, найденный в стеке, переполняет это сообщение: "Доступ не настроен. Используйте Google Developers Console для активации API для вашего проекта."

более конкретно этот ответ: fooobar.com/questions/89087/...

После этого я пошел в Google Developers Console и настроил Google+ API

И тогда, voillá! Это сработало.

Теперь код для получения токена доступа к токенам с использованием токена обновления (я не нашел возможности выполнить это с помощью 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;
    }
}

ВАЖНО 1: Чтобы получить токен обновления, вы должны установить "access_type" в "offline" в методе " ExecuteResult", следующим образом:

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

ВАЖНО 2:. Когда вы получите токен обновления, вы должны сохранить его и в каком-то защищенном источнике. API Google не выдаст вам новый токен обновления, если только вы не установите "assert_prompt" для "принудительного", прежде чем вы вызовете линию (в том же методе):

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

Я также рекомендую взглянуть на:

Автономный API Google API

Игровая площадка Google OAUTH 2.0

Проверка обнаружения API Google