【问题标题】:ASP.Net MVC5, Google OAuth 2.0 and Youtube APIASP.Net MVC5、谷歌 OAuth 2.0 和 Youtube API
【发布时间】:2014-10-06 04:05:10
【问题描述】:

我需要一些关于 mvc 5 的帮助,使用 google 登录提供程序并获取一些 youtube 数据。现在我想我把事情搞混了。我对 mvc 并不陌生,但对版本 5 的 owin 中间件功能并不陌生。好吧,在实施 oauth 2.0 方面没有经验。

我想要什么:

  • 通过 Google 登录我的 MVC5 应用程序。
  • 从登录用户那里读取一些 Youtube 信息。

到目前为止我做了什么:

  • 遵循此 Google OAuth 2.0 教程:Web applications (ASP.NET MVC)
    • 通过 NuGet 安装了 Google.Apis.Auth.MVC。
    • 按照描述实现了 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 时,它会将我重定向到谷歌,询问我的凭据。 输入时,系统会询问我是否同意应用程序要求的许可。确认后,我被重定向到我的页面,显示我的/Youtube/IndexAsync 页面以及请求的数据。到目前为止一切都很好,但这并不是我想要的。

我在这里所做的(我认为)我完全绕过了 asp.net 身份系统。用户没有登录我的应用程序,更不用说注册了。

我希望用户使用 google 登录,在我的应用程序中注册并提供对他的 youtube 数据的访问权限。然后,在特定页面上时,从用户的 youtube 帐户中检索数据。

我也尝试过:

  • 关注此ASP.Net MVC5 Tutorial
    • 本教程没有提到 NuGet 包“Google.Apis.Auth.MVC”,而是谈到了一个神奇的“/signin-google”重定向 uri”。
    • 这也有效,但破坏了上述解决方案,抱怨重定向 uri 错误。
    • 使用这种方法时,我似乎不适合再次在 YoutubeController 中调用 AuthorizeAsync,因为我应该已经获得授权。

所以我在黑暗中寻找一些光明,告诉我我正在混合在一起:) 我希望这个问题不会像我现在这样困惑。

【问题讨论】:

  • 也遇到了同样的问题,你解决了吗?
  • 不,抱歉。但仍然对答案感兴趣:)
  • @infadelic 我也面临同样的问题,你有解决办法吗?

标签: c# asp.net-mvc-5 youtube-api google-oauth


【解决方案1】:

我设法使用 GooglePlus 做到了这一点,还没有尝试过 Google。这是我所做的:

安装 nugets:

> 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. 启用身份验证通过。谷歌+
  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);
            }
        }
    }

您需要在 AccountController.cs 中的 2 个位置调用它:一次在 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

【讨论】:

  • Constants.GoogleAccessTokenConstants.GoogleRefreshToken 是什么?
  • @ebramtharwat 它们只是字符串。 GoogleAccessTokenurn:tokens:googleplus:accesstokenGoogleRefreshTokenurn:tokens:googleplus:refreshtoken。不过应该没什么区别。
猜你喜欢
  • 2015-02-14
  • 1970-01-01
  • 2017-07-31
  • 1970-01-01
  • 1970-01-01
  • 2015-01-10
  • 1970-01-01
  • 2012-11-13
  • 2013-05-07
相关资源
最近更新 更多