- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
在我的应用程序中,我使用 Google API V 3.0 .Net 库和 Google OAuth2 来同步 Google 日历和 Outlook 日历。我正在使用下面的代码来获取 Google.Apis.Calendar.v3.CalendarService 服务对象。在身份验证期间,我存储了 Json 文件,并从中请求 Google.Apis.Auth.OAuth2.UserCredential 对象。
private Google.Apis.Auth.OAuth2.UserCredential GetGoogleOAuthCredential()
{
GoogleTokenModel _TokenData = new GoogleTokenModel();
String JsonFilelocation = "jsonFileLocation;
Google.Apis.Auth.OAuth2.UserCredential credential = null;
using (var stream = new FileStream(JsonFilelocation, FileMode.Open,
FileAccess.Read))
{
Google.Apis.Auth.OAuth2.GoogleWebAuthorizationBroker.Folder = "Tasks.Auth.Store";
credential = Google.Apis.Auth.OAuth2.GoogleWebAuthorizationBroker.AuthorizeAsync(
Google.Apis.Auth.OAuth2.GoogleClientSecrets.Load(stream).Secrets,
new[] { Google.Apis.Calendar.v3.CalendarService.Scope.Calendar },
"user",
CancellationToken.None,
new FileDataStore("OGSync.Auth.Store")).Result;
}
return credential;
}
请求服务对象代码是:
Google.Apis.Calendar.v3.CalendarService _V3calendarService = new Google.Apis.Calendar.v3.CalendarService(new Google.Apis.Services.BaseClientService.Initializer()
{
HttpClientInitializer = GetGoogleOAuthCredential(),
ApplicationName = "TestApplication",
});
以上代码可以很好地获取 Calendarservice 对象。我的问题是,我的 Json 文件有刷新和访问 token 。当访问 token 过期时,上面的代码如何处理刷新 token 以获取服务?因为需要经常调用CalendarService对象,所以喜欢给calenderService对象实现单例模式。如何在不频繁调用 GetGoogleOAuthCredential 的情况下获取 Calendarservice?感谢您提供任何帮助/指导。
最佳答案
过去两天我自己解决了这个问题。除非您指定“access_type=offline”,否则库不会自动刷新 token 。
https://developers.google.com/api-client-library/dotnet/guide/aaa_oauth
我将粘贴我正在使用的代码,如果您有任何不明白的地方,尽管问。我已经阅读了很多帖子,现在我已经开始正常工作了,所以有一些注释代码,但它还没有被重构。我希望这会对某人有所帮助。我使用的 NuGet 包是这些:
Google.Apis.Auth.MVC
Google.Apis.Calendar.v3
代码:
AuthCallbackController:
[AuthorizationCodeActionFilter]
public class AuthCallbackController : Google.Apis.Auth.OAuth2.Mvc.Controllers.AuthCallbackController
{
protected static readonly ILogger Logger = ApplicationContext.Logger.ForType<AuthCallbackController>();
/// <summary>Gets the authorization code flow.</summary>
protected IAuthorizationCodeFlow Flow { get { return FlowData.Flow; } }
/// <summary>
/// Gets the user identifier. Potential logic is to use session variables to retrieve that information.
/// </summary>
protected string UserId { get { return FlowData.GetUserId(this); } }
/// <summary>
/// The authorization callback which receives an authorization code which contains an error or a code.
/// If a code is available the method exchange the coed with an access token and redirect back to the original
/// page which initialized the auth process (using the state parameter).
/// <para>
/// The current timeout is set to 10 seconds. You can change the default behavior by setting
/// <see cref="System.Web.Mvc.AsyncTimeoutAttribute"/> with a different value on your controller.
/// </para>
/// </summary>
/// <param name="authorizationCode">Authorization code response which contains the code or an error.</param>
/// <param name="taskCancellationToken">Cancellation token to cancel operation.</param>
/// <returns>
/// Redirect action to the state parameter or <see cref="OnTokenError"/> in case of an error.
/// </returns>
[AsyncTimeout(60000)]
public async override Task<ActionResult> IndexAsync(AuthorizationCodeResponseUrl authorizationCode,
CancellationToken taskCancellationToken)
{
if (string.IsNullOrEmpty(authorizationCode.Code))
{
var errorResponse = new TokenErrorResponse(authorizationCode);
Logger.Info("Received an error. The response is: {0}", errorResponse);
Debug.WriteLine("Received an error. The response is: {0}", errorResponse);
return OnTokenError(errorResponse);
}
Logger.Debug("Received \"{0}\" code", authorizationCode.Code);
Debug.WriteLine("Received \"{0}\" code", authorizationCode.Code);
var returnUrl = Request.Url.ToString();
returnUrl = returnUrl.Substring(0, returnUrl.IndexOf("?"));
var token = await Flow.ExchangeCodeForTokenAsync(UserId, authorizationCode.Code, returnUrl,
taskCancellationToken).ConfigureAwait(false);
// Extract the right state.
var oauthState = await AuthWebUtility.ExtracRedirectFromState(Flow.DataStore, UserId,
authorizationCode.State).ConfigureAwait(false);
return new RedirectResult(oauthState);
}
protected override Google.Apis.Auth.OAuth2.Mvc.FlowMetadata FlowData
{
get { return new AppFlowMetadata(); }
}
protected override ActionResult OnTokenError(TokenErrorResponse errorResponse)
{
throw new TokenResponseException(errorResponse);
}
//public class AuthCallbackController : Google.Apis.Auth.OAuth2.Mvc.Controllers.AuthCallbackController
//{
// protected override Google.Apis.Auth.OAuth2.Mvc.FlowMetadata FlowData
// {
// get { return new AppFlowMetadata(); }
// }
//}
Controller调用Google API的方法
public async Task<ActionResult> GoogleCalendarAsync(CancellationToken cancellationToken)
{
var result = await new AuthorizationCodeMvcApp(this, new AppFlowMetadata()).
AuthorizeAsync(cancellationToken);
if (result.Credential != null)
{
//var ttt = await result.Credential.RevokeTokenAsync(cancellationToken);
//bool x = await result.Credential.RefreshTokenAsync(cancellationToken);
var service = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = result.Credential,
ApplicationName = "GoogleApplication",
});
var t = service.Calendars;
var tt = service.CalendarList.List();
// Define parameters of request.
EventsResource.ListRequest request = service.Events.List("primary");
request.TimeMin = DateTime.Now;
request.ShowDeleted = false;
request.SingleEvents = true;
request.MaxResults = 10;
request.OrderBy = EventsResource.ListRequest.OrderByEnum.StartTime;
// List events.
Events events = request.Execute();
Debug.WriteLine("Upcoming events:");
if (events.Items != null && events.Items.Count > 0)
{
foreach (var eventItem in events.Items)
{
string when = eventItem.Start.DateTime.ToString();
if (String.IsNullOrEmpty(when))
{
when = eventItem.Start.Date;
}
Debug.WriteLine("{0} ({1})", eventItem.Summary, when);
}
}
else
{
Debug.WriteLine("No upcoming events found.");
}
//Event myEvent = new Event
//{
// Summary = "Appointment",
// Location = "Somewhere",
// Start = new EventDateTime()
// {
// DateTime = new DateTime(2014, 6, 2, 10, 0, 0),
// TimeZone = "America/Los_Angeles"
// },
// End = new EventDateTime()
// {
// DateTime = new DateTime(2014, 6, 2, 10, 30, 0),
// TimeZone = "America/Los_Angeles"
// },
// Recurrence = new String[] {
// "RRULE:FREQ=WEEKLY;BYDAY=MO"
// },
// Attendees = new List<EventAttendee>()
// {
// new EventAttendee() { Email = "johndoe@gmail.com" }
// }
//};
//Event recurringEvent = service.Events.Insert(myEvent, "primary").Execute();
return View();
}
else
{
return new RedirectResult(result.RedirectUri);
}
}
FlowMetadata 的派生类
public class AppFlowMetadata : FlowMetadata
{
//static readonly string server = ConfigurationManager.AppSettings["DatabaseServer"];
//static readonly string serverUser = ConfigurationManager.AppSettings["DatabaseUser"];
//static readonly string serverPassword = ConfigurationManager.AppSettings["DatabaseUserPassword"];
//static readonly string serverDatabase = ConfigurationManager.AppSettings["DatabaseName"];
////new FileDataStore("Daimto.GoogleCalendar.Auth.Store")
////new FileDataStore("Drive.Api.Auth.Store")
//static DatabaseDataStore databaseDataStore = new DatabaseDataStore(server, serverUser, serverPassword, serverDatabase);
private static readonly IAuthorizationCodeFlow flow =
new ForceOfflineGoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = new ClientSecrets
{
ClientId = "yourClientId",
ClientSecret = "yourClientSecret"
},
Scopes = new[]
{
CalendarService.Scope.Calendar, // Manage your calendars
//CalendarService.Scope.CalendarReadonly // View your Calendars
},
DataStore = new EFDataStore(),
});
public override string GetUserId(Controller controller)
{
// In this sample we use the session to store the user identifiers.
// That's not the best practice, because you should have a logic to identify
// a user. You might want to use "OpenID Connect".
// You can read more about the protocol in the following link:
// https://developers.google.com/accounts/docs/OAuth2Login.
//var user = controller.Session["user"];
//if (user == null)
//{
// user = Guid.NewGuid();
// controller.Session["user"] = user;
//}
//return user.ToString();
//var store = new UserStore<ApplicationUser>(new ApplicationDbContext());
//var manager = new UserManager<ApplicationUser>(store);
//var currentUser = manager.FindById(controller.User.Identity.GetUserId());
return controller.User.Identity.GetUserId();
}
public override IAuthorizationCodeFlow Flow
{
get { return flow; }
}
public override string AuthCallback
{
get { return @"/GoogleApplication/AuthCallback/IndexAsync"; }
}
}
Entity Framework 6 DataStore类
public class EFDataStore : IDataStore
{
public async Task ClearAsync()
{
using (var context = new ApplicationDbContext())
{
var objectContext = ((IObjectContextAdapter)context).ObjectContext;
await objectContext.ExecuteStoreCommandAsync("TRUNCATE TABLE [Items]");
}
}
public async Task DeleteAsync<T>(string key)
{
if (string.IsNullOrEmpty(key))
{
throw new ArgumentException("Key MUST have a value");
}
using (var context = new ApplicationDbContext())
{
var generatedKey = GenerateStoredKey(key, typeof(T));
var item = context.GoogleAuthItems.FirstOrDefault(x => x.Key == generatedKey);
if (item != null)
{
context.GoogleAuthItems.Remove(item);
await context.SaveChangesAsync();
}
}
}
public Task<T> GetAsync<T>(string key)
{
if (string.IsNullOrEmpty(key))
{
throw new ArgumentException("Key MUST have a value");
}
using (var context = new ApplicationDbContext())
{
var generatedKey = GenerateStoredKey(key, typeof(T));
var item = context.GoogleAuthItems.FirstOrDefault(x => x.Key == generatedKey);
T value = item == null ? default(T) : JsonConvert.DeserializeObject<T>(item.Value);
return Task.FromResult<T>(value);
}
}
public async Task StoreAsync<T>(string key, T value)
{
if (string.IsNullOrEmpty(key))
{
throw new ArgumentException("Key MUST have a value");
}
using (var context = new ApplicationDbContext())
{
var generatedKey = GenerateStoredKey(key, typeof(T));
string json = JsonConvert.SerializeObject(value);
var item = await context.GoogleAuthItems.SingleOrDefaultAsync(x => x.Key == generatedKey);
if (item == null)
{
context.GoogleAuthItems.Add(new GoogleAuthItem { Key = generatedKey, Value = json });
}
else
{
item.Value = json;
}
await context.SaveChangesAsync();
}
}
private static string GenerateStoredKey(string key, Type t)
{
return string.Format("{0}-{1}", t.FullName, key);
}
}
GoogleAuthorizationCodeFlow 的派生类。启用负责自动“刷新” token 的长期刷新 token ,这仅意味着获取新的访问 token 。
https://developers.google.com/api-client-library/dotnet/guide/aaa_oauth
internal class ForceOfflineGoogleAuthorizationCodeFlow : GoogleAuthorizationCodeFlow
{
public ForceOfflineGoogleAuthorizationCodeFlow(GoogleAuthorizationCodeFlow.Initializer initializer) : base (initializer) { }
public override AuthorizationCodeRequestUrl CreateAuthorizationCodeRequest(string redirectUri)
{
return new GoogleAuthorizationCodeRequestUrl(new Uri(AuthorizationServerUrl))
{
ClientId = ClientSecrets.ClientId,
Scope = string.Join(" ", Scopes),
RedirectUri = redirectUri,
AccessType = "offline",
ApprovalPrompt = "force"
};
}
}
GoogleAuthItem 与 EFDataStore 一起使用
public class GoogleAuthItem
{
[Key]
[MaxLength(100)]
public string Key { get; set; }
[MaxLength(500)]
public string Value { get; set; }
}
public DbSet<GoogleAuthItem> GoogleAuthItems { get; set; }
关于c# - Google API V 3.0 .Net 库和 Google OAuth2 如何处理刷新 token ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26098009/
我们知道,当使用 hibernate 对数据库进行批量更新时(即使在 HQL 中),所做的更改不会复制到存储在当前 session 中的实体。 所以我可以调用 session.refresh 来加载对
我正在做一个项目,所有的东西都保存在事件中,所以服务器需要一些时间来响应新数据。我正在使用 Fluent 等待使用 ajax 的页面,但是这个不使用任何 ajax。所以我想刷新页面检查是否有新项目,如
我有一个从 Vector 创建的 JTable。 如何刷新 JTable 以显示添加到 Vector 的新数据? 最佳答案 当 TableModel 发生更改时,您的 JTable 应该会自动更新。我
有没有办法使用下面的代码来刷新已经存在的 div id,而不是刷新时间? window.onload = startInterval; function startInterval() {
我更新了在 Shiny Server 上运行的 Shiny 应用程序使用的 DataSet.RData。但是, Shiny 的应用程序仍在旧数据上运行。我已通过浏览器历史记录清除并重新启动浏览器几次,
我的应用程序中有一个无限滚动的网格面板(ExtJs 4.2.1),类似于 this example .用户可以单击刷新按钮,然后必须使用数据库中的数据更新网格的行。我在刷新按钮处理程序中调用 stor
我不知道这三种方法中哪一种最适合我。他们都为我工作。有谁知道刷新、更新和重画之间的区别吗? 最佳答案 根据在线文档: Refresh - 重新绘制屏幕上的控件。 Call Refresh method
有什么办法吗 ICollectionView.Refresh() 或者 CollectionViewSource.GetDefaultView(args.NewValue).Refresh(); 在
这个问题已经有答案了: Updating address bar with new URL without hash or reloading the page [duplicate] (4 个回答)
我有一个 javascript 设置超时以在 10 秒后关闭 div,并且我想在 div 关闭时添加页面刷新。我正在使用的代码如下。 var container_close_sec = "1
我有一组具有以下名称的页面.... update1.php update2.php update3.php update4.php update5.php update6.php update7.ph
如果是则触发js函数。我可以使一个复选框保持选中状态,并在页面刷新时检查值并选中“checked”,并提交以下内容... checked="checked" /> 你都不记得触发js函数。 这是我的
我正在尝试刷新 php 脚本以在数据库更新时显示更新的内容。我首先构建了我的 php,然后刷新代码,然后合并它们。但是,脚本不会更新。有谁知道为什么吗? $(document).ready
当我要删除的节点扩展集合类型时,Grails中有一个错误阻止我使用removeFrom *。直接从关联中删除节点不会更新二级缓存。 A hasMany B 有什么方法可以使关联缓存手动无效或强制重新加
我正在使用 hibernate 和 mysql 来抽象一个数据库,以便在 java 驱动的网站中使用。我使用 hibernate 很好地解决了所有查询,但似乎无法弄清楚如何使用它进行更新、插入和删除,
如何通过调用 oncreateview 方法重新创建 fragment ?我有一个 fragment ,用于通过表单插入新数据,单击按钮后,我想通过删除在 EditText 中输入的数据来重新创建 f
当我从一个到另一个时,我试图刷新我的观点。我知道我应该将刷新代码放在 viewWillAppear 中,但我不知道该放什么代码。 你们能帮帮我吗? 谢谢! 最佳答案 在您看来,请调用 setNeeds
我正在开发 iPhone 应用程序并希望使用: CFStreamCreatePairWithSocketToHost(NULL, url, port, &serverReadStream, &serv
看到我已经创建了一个用于登录用户的脚本。而且我还添加了设置选项卡,以便用户可以编辑他们的设置!但是当我尝试它时,mysql 表中的数据发生了变化,但配置文件中显示的用户名和用户电子邮件保持不变!当我注
好的。这就是它的样子。 当我启动应用程序时,我从服务器收到的第一件事是数据: {name: "test", type: "checkbox" checked: true, } 这使得其中一个复选框
我是一名优秀的程序员,十分优秀!