ASP.Net MVC5, Google OAuth 2.0 и API Youtube

Мне нужна помощь в отношении mvc 5 с использованием провайдера входа в Google и получения некоторых данных YouTube. сейчас я думаю, что я немного перепутал. Я не новичок в mvc, но в функциях промежуточного программного обеспечения owin версии 5. ну и не опытный в реализации oauth 2.0.

Что я хочу:

  • Войдите в мое приложение MVC5 через Google.
  • Прочитайте некоторую информацию Youtube от вошедшего в систему пользователя.

Что я сделал до сих пор:

  • Followed this Google OAuth 2.0 tutorial: Web applications (ASP.NET MVC).
    • Installed Google.Apis.Auth.MVC via NuGet.
    • Реализованы AppFlowMetadata и AuthCallbackController, как описано.
    • Настроил URI перенаправления на «/AuthCallback/IndexAsync», как описано.
  • Реализовал YoutubeController со следующим действием только для вывода некоторых данных:

    public async Task<ActionResult> IndexAsync()
    {
        var result =
            await new AuthorizationCodeMvcApp(this, new AppFlowMetadata())
            .AuthorizeAsync(cancellationToken);
    
        if (result.Credential == null)
        {
            return new RedirectResult(result.RedirectUri);
        }
        else
        {
            var service = new YouTubeService(new BaseClientService.Initializer
                {
                    HttpClientInitializer = result.Credential,
                    ApplicationName = "MyYoutubeApplication"
                });
    
            var playlists = service.Playlists.List("contentDetails, snippet");
            playlists.Mine = true;
    
            var list = await playlists.ExecuteAsync();
            var json = new JavaScriptSerializer().Serialize(list);
    
            ViewBag.Message = json; 
            return View();
        }
    }
    

Итак, что это делает, когда при попытке доступа к /Youtube/IndexAsync меня перенаправляют в Google, запрашивая мои учетные данные. при входе меня спрашивают, согласен ли я с разрешением, запрашиваемым приложением. после подтверждения меня перенаправляют на мою страницу, показывая мою /Youtube/IndexAsync страницу с запрошенными данными. пока все хорошо, но это не совсем то, что я хочу.

что (я думаю) я сделал здесь, так это то, что я полностью обошел систему идентификации asp.net. пользователь не вошел в мое приложение, не говоря уже о регистрации.

я хочу, чтобы пользователь вошел в систему с помощью Google, зарегистрировался в моем приложении и предоставил доступ к своим данным YouTube. затем, находясь на определенной странице, получить данные из учетной записи пользователя YouTube.

Что я также пробовал:

  • Following this ASP.Net MVC5 Tutorial
    • This tutorial does not mention the NuGet package "Google.Apis.Auth.MVC" and talks something about a magic "/signin-google" redirect uri".
    • Это также работает, но нарушает приведенное выше решение, жалуясь на неправильный uri перенаправления.
    • При использовании этого подхода мне кажется неправильным снова вызывать AuthorizeAsync в YoutubeController, поскольку я уже должен быть авторизован.

Так что я ищу немного света в темноте, рассказывая мне, что я смешиваю все вместе :) Я надеюсь, что вопрос не так запутан, как я сейчас.


person chris vietor    schedule 12.08.2014    source источник
comment
тоже такая же проблема, вы решили ее?   -  person galdin    schedule 28.10.2014
comment
нет извини. но все же интересен ответ :)   -  person chris vietor    schedule 30.10.2014
comment
@infadelic У меня та же проблема, вы нашли какое-нибудь решение?   -  person ebram khalil    schedule 04.11.2014


Ответы (1)


Мне удалось сделать это с помощью GooglePlus, не пробовал Google. Вот что я сделал:

Установите нужеты:

> Install-Package Owin.Security.Providers
> Install-Package Google.Apis.Youtube.v3

Добавьте это в Startup.auth.cs:

var g = new GooglePlusAuthenticationOptions();
g.ClientId = Constants.GoogleClientId;
g.ClientSecret = Constants.GoogleClientSecret;
g.RequestOfflineAccess = true;  // for refresh token
g.Provider = new GooglePlusAuthenticationProvider
{
    OnAuthenticated = context =>
    {
        context.Identity.AddClaim(new Claim(Constants.GoogleAccessToken, context.AccessToken));
        if (!String.IsNullOrEmpty(context.RefreshToken))
        {
            context.Identity.AddClaim(new Claim(Constants.GoogleRefreshToken, context.RefreshToken));
        }
        return Task.FromResult<object>(null);
    }
};

g.Scope.Add(Google.Apis.YouTube.v3.YouTubeService.Scope.YoutubeReadonly);
g.SignInAsAuthenticationType = DefaultAuthenticationTypes.ExternalCookie;
app.UseGooglePlusAuthentication(g);

Приведенный выше код делает две вещи:

  1. Включите аутентификацию через. Google+
  2. Запросы токена доступа и токена обновления. Затем токены добавляются как утверждение в промежуточное ПО GooglePlus.

Создайте метод, который будет хранить утверждения, содержащие токен, в базе данных. У меня есть это в файле AccountController.cs

private async Task StoreGooglePlusAuthToken(ApplicationUser user)
{
    var claimsIdentity = await AuthenticationManager.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie);
    if (claimsIdentity != null)
    {
        // Retrieve the existing claims for the user and add the google plus access token
        var currentClaims = await UserManager.GetClaimsAsync(user.Id);
        var ci = claimsIdentity.FindAll(Constants.GoogleAccessToken);
        if (ci != null && ci.Count() != 0)
        {
            var accessToken = ci.First();
            if (currentClaims.Count() <= 0)
            {
                await UserManager.AddClaimAsync(user.Id, accessToken);
            }
        }

        ci = claimsIdentity.FindAll(Constants.GoogleRefreshToken);
        if (ci != null && ci.Count() != 0)
        {
            var refreshToken = ci.First();
            if (currentClaims.Count() <= 1)
            {
                await UserManager.AddClaimAsync(user.Id, refreshToken);
            }
        }
    }

Вам нужно будет вызвать его в 2 местах в AccountController.cs: Один раз в ExternalLoginCallback:

case SignInStatus.Success:
var currentUser = await UserManager.FindAsync(loginInfo.Login);
if (currentUser != null)
{
    await StoreGooglePlusAuthToken(currentUser);
}
return RedirectToLocal(returnUrl);

и один раз в ExternalLoginConfirmation:

var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
var result = await UserManager.CreateAsync(user);
if (result.Succeeded)
{
    result = await UserManager.AddLoginAsync(user.Id, info.Login);
    if (result.Succeeded)
    {
        await StoreGooglePlusAuthToken(user);
        await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
        return RedirectToLocal(returnUrl);
    }
}

Теперь, когда у нас есть токен доступа пользователя и токен обновления, мы можем использовать его для аутентификации пользователя.

Я попробовал простой поиск, который видел в примерах, и он сработал:

private async Task<Models.YouTubeViewModel> Search(string searchTerm)
{
    var user = (ClaimsPrincipal)Thread.CurrentPrincipal;

    var at = user.Claims.FirstOrDefault(x => x.Type == Constants.GoogleAccessToken);
    var rt = user.Claims.FirstOrDefault(x => x.Type == Constants.GoogleRefreshToken);

    if (at == null || rt == null)
        throw new HttpUnhandledException("Access / Refresh Token missing");

    TokenResponse token = new TokenResponse
    {
        AccessToken = at.Value,
        RefreshToken = rt.Value
    };

    var cred = new UserCredential(new GoogleAuthorizationCodeFlow(
                new GoogleAuthorizationCodeFlow.Initializer()
                {
                    ClientSecrets = new ClientSecrets()
                                    {
                                        ClientId = Constants.GoogleClientId,
                                        ClientSecret = Constants.GoogleClientSecret
                                    }
                }
            ),
            User.Identity.GetApplicationUser().UserName,
            token
        );

    var youtubeService = new YouTubeService(new BaseClientService.Initializer()
    {
        ApplicationName = this.GetType().ToString(),
        HttpClientInitializer = cred,
    });

    var searchListRequest = youtubeService.Search.List("snippet");
    searchListRequest.Q = searchTerm;
    searchListRequest.MaxResults = 50;

    // Call the search.list method to retrieve results matching the specified query term.
    var searchListResponse = await searchListRequest.ExecuteAsync();

    Models.YouTubeViewModel vm = new Models.YouTubeViewModel(searchTerm);
    foreach (var searchResult in searchListResponse.Items)
    {
        switch (searchResult.Id.Kind)
        {
            case "youtube#video":
                vm.Videos.Add(new Models.Result(searchResult.Snippet.Title, searchResult.Id.VideoId));
                break;

            case "youtube#channel":
                vm.Channels.Add(new Models.Result(searchResult.Snippet.Title, searchResult.Id.ChannelId));
                break;

            case "youtube#playlist":
                vm.Playlists.Add(new Models.Result(searchResult.Snippet.Title, searchResult.Id.PlaylistId));
                break;
        }
    }

    return vm;
}

Классы моделей

public class Result 
{
    public string Title { get; set; }
    public string Id { get; set; }

    public Result() { }

    public Result(string title, string id)
    {
        this.Title = title;
        this.Id = id;
    }
}

public class YouTubeViewModel
{
    public string SearchTerm { get; set; }

    public List<Result> Videos { get; set; }
    public List<Result> Playlists { get; set; }
    public List<Result> Channels { get; set; }

    public YouTubeViewModel()
    {
        Videos = new List<Result>();
        Playlists = new List<Result>();
        Channels = new List<Result>();
    }

    public YouTubeViewModel(string searchTerm)
        :this()
    {
        SearchTerm = searchTerm;
    }
}

Ссылка: http://blogs.msdn.com/b/webdev/archive/2013/10/16/get-more-information-from-social-providers-used-in-the-vs-2013.-project-templates.aspx

person galdin    schedule 30.10.2014
comment
Что такое Constants.GoogleAccessToken и Constants.GoogleRefreshToken? - person ebram khalil; 04.11.2014
comment
@ebramtharwat это просто строки. GoogleAccessToken это urn:tokens:googleplus:accesstoken, а GoogleRefreshToken это urn:tokens:googleplus:refreshtoken. Хотя не должно иметь никакого значения. - person galdin; 09.11.2014