.NET 5 MVC应用集成Google Calendar,如何跳过控制台获取用户凭证?
.NET 5 MVC Google Calendar OAuth流程优化方案
核心优化思路
将本地credentials.json的配置迁移至应用配置中心,使用Google官方OAuth客户端库替代手动拼接授权URL,同时通过应用内登录校验确保用户无需接触Google控制台,仅需完成应用登录即可触发授权流程,并将凭证自动存入自有数据库。
步骤1:迁移凭证配置到appsettings.json
将Google控制台获取的客户端信息移至应用配置文件,避免依赖本地文件:
"GoogleCalendarSettings": { "ClientId": "你的Google客户端ID", "ClientSecret": "你的Google客户端密钥", "RedirectUri": "https://localhost:44311/Reservation/CalendarCallback", "Scopes": [ "https://www.googleapis.com/auth/calendar", "https://www.googleapis.com/auth/calendar.events" ] }
步骤2:安装Google官方授权库
通过NuGet安装依赖包:
Install-Package Google.Apis.Auth.Mvc Install-Package Google.Apis.Calendar.v3 Install-Package Newtonsoft.Json
步骤3:改造授权跳转与回调逻辑
替换手动拼接URL的方式,使用官方库生成授权请求,并处理回调获取凭证:
using Google.Apis.Auth.OAuth2; using Google.Apis.Auth.Mvc; using Google.Apis.Calendar.v3; using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.Configuration; using Newtonsoft.Json; using System.Threading; using System.Threading.Tasks; public class ReservationController : Controller { private readonly IConfiguration _configuration; private readonly YourDbContext _dbContext; public ReservationController(IConfiguration configuration, YourDbContext dbContext) { _configuration = configuration; _dbContext = dbContext; } // 要求用户先完成应用登录 [Authorize] public ActionResult InitiateCalendarAuth() { var settings = _configuration.GetSection("GoogleCalendarSettings"); var clientSecrets = new ClientSecrets { ClientId = settings["ClientId"], ClientSecret = settings["ClientSecret"] }; var flow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer { ClientSecrets = clientSecrets, Scopes = settings.GetSection("Scopes").Get<string[]>(), DataStore = new DatabaseDataStore(_dbContext) }); var authorizationUrl = flow.CreateAuthorizationCodeRequest(settings["RedirectUri"]) .SetAccessType("offline") .SetIncludeGrantedScopes(true) .SetState(User.Identity.Name) // 用登录用户标识关联凭证 .Build(); return Redirect(authorizationUrl.ToString()); } // Google授权回调处理 public async Task<ActionResult> CalendarCallback(string code, string state) { var settings = _configuration.GetSection("GoogleCalendarSettings"); var clientSecrets = new ClientSecrets { ClientId = settings["ClientId"], ClientSecret = settings["ClientSecret"] }; var flow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer { ClientSecrets = clientSecrets, Scopes = settings.GetSection("Scopes").Get<string[]>(), DataStore = new DatabaseDataStore(_dbContext) }); // 交换授权码获取凭证,自动存入数据库 await flow.ExchangeCodeForTokenAsync( userId: state, code: code, redirectUri: settings["RedirectUri"], cancellationToken: CancellationToken.None); return RedirectToAction("Calendar"); } }
步骤4:实现数据库凭证存储
自定义IDataStore实现,将凭证直接存入自有数据库:
using Google.Apis.Util.Store; using Microsoft.EntityFrameworkCore; using Newtonsoft.Json; using System.Threading; using System.Threading.Tasks; public class DatabaseDataStore : IDataStore { private readonly YourDbContext _dbContext; public DatabaseDataStore(YourDbContext dbContext) { _dbContext = dbContext; } public async Task StoreAsync<T>(string key, T value) { var json = JsonConvert.SerializeObject(value); var credential = await _dbContext.UserCalendarCredentials .FirstOrDefaultAsync(c => c.UserId == key); if (credential != null) { credential.CredentialJson = json; } else { _dbContext.UserCalendarCredentials.Add(new UserCalendarCredential { UserId = key, CredentialJson = json }); } await _dbContext.SaveChangesAsync(); } public async Task<T> GetAsync<T>(string key) { var credential = await _dbContext.UserCalendarCredentials .FirstOrDefaultAsync(c => c.UserId == key); return credential == null ? default : JsonConvert.DeserializeObject<T>(credential.CredentialJson); } public async Task DeleteAsync<T>(string key) { var credential = await _dbContext.UserCalendarCredentials .FirstOrDefaultAsync(c => c.UserId == key); if (credential != null) { _dbContext.UserCalendarCredentials.Remove(credential); await _dbContext.SaveChangesAsync(); } } public async Task ClearAsync() { _dbContext.UserCalendarCredentials.RemoveRange(_dbContext.UserCalendarCredentials); await _dbContext.SaveChangesAsync(); } } // 数据库实体类示例 public class UserCalendarCredential { public int Id { get; set; } public string UserId { get; set; } public string CredentialJson { get; set; } }
优化效果
- 移除本地文件依赖,配置集中管理,适配部署场景
- 官方库处理授权流程,避免手动拼接URL的潜在错误
- 应用登录校验前置,用户无需接触Google控制台
- 凭证自动关联登录用户并存入数据库,无需手动操作
内容的提问来源于stack exchange,提问作者Wannes Limbourg
相关产品推荐
相关产品推荐

