Ste*_*ter 2 c# google-api youtube-api asp.net-core asp.net-core-1.1
我想在 .NET Core 1.1 中编写一个小型的个人 Web 应用程序来与 YouTube 交互并让我更轻松地做一些事情,我正在关注Google 的 YouTube 文档中的教程/示例。听起来很简单,对吧?;)
使用 Google 的 API 进行身份验证似乎是不可能的!我做了以下工作:
但是,当我尝试使用 Google 的 API 进行身份验证时,收到以下错误:
- 那是一个错误。
错误:redirect_uri_mismatch
请求中的重定向 URI http://127.0.0.1:63354/authorize/与为 OAuth 客户端授权的不匹配。
所以现在,对于这个问题。在为此寻找解决方案时,我唯一能找到的是人们说
只需将重定向 URI 放在您批准的重定向 URI 中
不幸的是,问题是每次我的代码尝试使用 Google 的 API 进行身份验证时,它使用的重定向 URI 都会发生变化(即使我在项目的属性中设置了静态端口,端口也会发生变化)。我似乎找不到让它使用静态端口的方法。任何帮助或信息都会很棒!
注意:请不要说诸如“你为什么不这样做根本不能回答你的问题”之类的话。
client_id.json
{
"web": {
"client_id": "[MY_CLIENT_ID]",
"project_id": "[MY_PROJECT_ID]",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://accounts.google.com/o/oauth2/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_secret": "[MY_CLIENT_SECRET]",
"redirect_uris": [
"http://127.0.0.1:60077/authorize/"
]
}
}
Run Code Online (Sandbox Code Playgroud)
尝试使用 API 的方法
public async Task<IActionResult> Test()
{
string ClientIdPath = @"C:\Path\To\My\client_id.json";
UserCredential credential;
using (var stream = new FileStream(ClientIdPath, FileMode.Open, FileAccess.Read))
{
credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
new[] { YouTubeService.Scope.YoutubeReadonly },
"user",
CancellationToken.None,
new FileDataStore(this.GetType().ToString())
);
}
var youtubeService = new YouTubeService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = this.GetType().ToString()
});
var channelsListRequest = youtubeService.Channels.List("contentDetails");
channelsListRequest.Mine = true;
// Retrieve the contentDetails part of the channel resource for the authenticated user's channel.
var channelsListResponse = await channelsListRequest.ExecuteAsync();
return Ok(channelsListResponse);
}
Run Code Online (Sandbox Code Playgroud)
项目属性
所以,我想通了这一点。问题在于 Google 将 Web 应用程序视为基于 JavaScript 的 Web 应用程序,而不是具有服务器端处理功能的 Web 应用程序。因此,您不能在 Google Developer Console 中为基于服务器的 Web 应用程序创建 Web 应用程序 OAuth 客户端 ID。
解决方法是在 Google Developer Console 中创建 OAuth Client ID 时选择其他类型。这将使 Google 将其视为已安装的应用程序而不是 JavaScript 应用程序,因此不需要重定向 URI 来处理回调。
这有点令人困惑,因为 Google 的 .NET 文档告诉您创建一个 Web App OAuth 客户端 ID。
我想提供此答案的更新。虽然,我上面所说的有效,但这不是为 ASP.NET 解决方案实现 OAuth 工作流的最佳方式。有一种更好的方法实际上使用了正确的 OAuth 2.0 流程。Google 的文档在这方面很糟糕(尤其是对于 .NET),所以我将在这里提供一个简单的实现示例。该示例使用 ASP.NET 核心,但它很容易适应完整的 .NET 框架 :)
注意: Google 确实有一个 Google.Apis.Auth.MVC 包来帮助简化此 OAuth 2.0 流程,但不幸的是,它与特定的 MVC 实现耦合,并且不适用于 ASP.NET Core 或 Web API。所以,我不会使用它。我将给出的示例适用于所有 ASP.NET 应用程序。相同的代码流可用于您启用的任何 Google API,因为它取决于您请求的范围。
另外,我假设您在 Google Developer 仪表板中设置了您的应用程序。也就是说,您已经创建了一个应用程序,启用了必要的 YouTube API,创建了一个 Web 应用程序客户端,并正确设置了允许的重定向 URL。
流程将像这样工作:
您需要以下 NuGet 包
该模型
public class ExampleModel
{
public bool UserHasYoutubeToken { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
控制器
public class ExampleController : Controller
{
// I'm assuming you have some sort of service that can read users from and update users to your database
private IUserService userService;
public ExampleController(IUserService userService)
{
this.userService = userService;
}
public async Task<IActionResult> Index()
{
var userId = // Get your user's ID however you get it
// I'm assuming you have some way of knowing if a user has an access token for YouTube or not
var userHasToken = this.userService.UserHasYoutubeToken(userId);
var model = new ExampleModel { UserHasYoutubeToken = userHasToken }
return View(model);
}
// This is a method we'll use to obtain the authorization code flow
private AuthorizationCodeFlow GetGoogleAuthorizationCodeFlow(params string[] scopes)
{
var clientIdPath = @"C:\Path\To\My\client_id.json";
using (var fileStream = new FileStream(clientIdPath, FileMode.Open, FileAccess.Read))
{
var clientSecrets = GoogleClientSecrets.Load(stream).Secrets;
var initializer = new GoogleAuthorizationCodeFlow.Initializer { ClientSecrets = clientSecrets, Scopes = scopes };
var googleAuthorizationCodeFlow = new GoogleAuthorizationCodeFlow(initializer);
return googleAuthorizationCodeFlow;
}
}
// This is a route that your View will call (we'll call it using JQuery)
[HttpPost]
public async Task<string> GetAuthorizationUrl()
{
// First, we need to build a redirect url that Google will use to redirect back to the application after the user grants access
var protocol = Request.IsHttps ? "https" : "http";
var redirectUrl = $"{protocol}://{Request.Host}/{Url.Action(nameof(this.GetYoutubeAuthenticationToken)).TrimStart('/')}";
// Next, let's define the scopes we'll be accessing. We are requesting YouTubeForceSsl so we can manage a user's YouTube account.
var scopes = new[] { YouTubeService.Scope.YoutubeForceSsl };
// Now, let's grab the AuthorizationCodeFlow that will generate a unique authorization URL to redirect our user to
var googleAuthorizationCodeFlow = this.GetGoogleAuthorizationCodeFlow(scopes);
var codeRequestUrl = googleAuthorizationCodeFlow.CreateAuthorizationCodeRequest(redirectUrl);
codeRequestUrl.ResponseType = "code";
// Build the url
var authorizationUrl = codeRequestUrl.Build();
// Give it back to our caller for the redirect
return authorizationUrl;
}
public async Task<IActionResult> GetYoutubeAuthenticationToken([FromQuery] string code)
{
if(string.IsNullOrEmpty(code))
{
/*
This means the user canceled and did not grant us access. In this case, there will be a query parameter
on the request URL called 'error' that will have the error message. You can handle this case however.
Here, we'll just not do anything, but you should write code to handle this case however your application
needs to.
*/
}
// The userId is the ID of the user as it relates to YOUR application (NOT their Youtube Id).
// This is the User ID that you assigned them whenever they signed up or however you uniquely identify people using your application
var userId = // Get your user's ID however you do (whether it's on a claim or you have it stored in session or somewhere else)
// We need to build the same redirect url again. Google uses this for validaiton I think...? Not sure what it's used for
// at this stage, I just know we need it :)
var protocol = Request.IsHttps ? "https" : "http";
var redirectUrl = $"{protocol}://{Request.Host}/{Url.Action(nameof(this.GetYoutubeAuthenticationToken)).TrimStart('/')}";
// Now, let's ask Youtube for our OAuth token that will let us do awesome things for the user
var scopes = new[] { YouTubeService.Scope.YoutubeForceSsl };
var googleAuthorizationCodeFlow = this.GetYoutubeAuthorizationCodeFlow(scopes);
var token = await googleAuthorizationCodeFlow.ExchangeCodeForTokenAsync(userId, code, redirectUrl, CancellationToken.None);
// Now, you need to store this token in rlation to your user. So, however you save your user data, just make sure you
// save the token for your user. This is the token you'll use to build up the UserCredentials needed to act on behalf
// of the user.
var tokenJson = JsonConvert.SerializeObject(token);
await this.userService.SaveUserToken(userId, tokenJson);
// Now that we've got access to the user's YouTube account, let's get back
// to our application :)
return RedirectToAction(nameof(this.Index));
}
}
Run Code Online (Sandbox Code Playgroud)
风景
@using YourApplication.Controllers
@model YourApplication.Models.ExampleModel
<div>
@if(Model.UserHasYoutubeToken)
{
<p>YAY! We have access to your YouTube account!</p>
}
else
{
<button id="addYoutube">Add YouTube</button>
}
</div>
<script>
$(document).ready(function () {
var addYoutubeUrl = '@Url.Action(nameof(ExampleController.GetAuthorizationUrl))';
// When the user clicks the 'Add YouTube' button, we'll call the server
// to get the Authorization URL Google built for us, then redirect the
// user to it.
$('#addYoutube').click(function () {
$.post(addYoutubeUrl, function (result) {
if (result) {
window.location.href = result;
}
});
});
});
</script>
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4240 次 |
| 最近记录: |