使用 C# 使用 Google OAuth 2.0 登录

2024-04-19

我想允许用户使用登录Gmail。因此,我在 google 上搜索并获得了许多示例,但所有示例都使用 OpenID,而且我检查了 Google 文档,他们已停止 OpenID 的新域注册,从现在开始,开发人员将需要使用 OAuth API。

我已经注册了我的项目并获得了 Secret KEY 和 Client ID。现在我想将其集成到我的项目中,但我找不到任何示例工作项目。

请帮助我解决这个问题。我没有使用 MVC。


我正在基于Google+ API进行解释,它使用Gmail ID登录。因此,您将验证您的用户是否可以使用 Gmail 登录。

1:您需要开启Google+ API:

2:开启Google+ API后,您需要添加新的Client ID.

Step 2
Step 3

在步骤 2 中,当您添加重定向 URL 时,您需要添加您希望用户重定向到的页面的网站 URL。

创建 Web 应用程序的客户端 ID 后。

然后在您的应用程序中,您需要添加两个包

1: Newtonsoft.Json
2: Microsoft.Net.Http

现在添加这个命名空间;

using Newtonsoft.Json;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

现在,首先在代码中在页面顶部声明此变量;

protected string googleplus_client_id = "458878619548-khuatamj3qpiccnsm4q6dbulf13jumva.apps.googleusercontent.com";    // Replace this with your Client ID
protected string googleplus_client_secret = "4hiVJYlomswRd_PV5lyNQlfN";                                                // Replace this with your Client Secret
protected string googleplus_redirect_url = "http://localhost:2443/Index.aspx";                                         // Replace this with your Redirect URL; Your Redirect URL from your developer.google application should match this URL.
protected string Parameters;

然后在页面加载事件中;

protected void Page_Load(object sender, EventArgs e)
{
    if ((Session.Contents.Count > 0) && (Session["loginWith"] != null) && (Session["loginWith"].ToString() == "google"))
    {
        try
        {
            var url = Request.Url.Query;
            if (url != "")
            {
                string queryString = url.ToString();
                char[] delimiterChars = { '=' };
                string[] words = queryString.Split(delimiterChars);
                string code = words[1];

                if (code != null)
                {
                    //get the access token 
                    HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create("https://accounts.google.com/o/oauth2/token");
                    webRequest.Method = "POST";
                    Parameters = "code=" + code + "&client_id=" + googleplus_client_id + "&client_secret=" + googleplus_client_secret + "&redirect_uri=" + googleplus_redirect_url + "&grant_type=authorization_code";
                    byte[] byteArray = Encoding.UTF8.GetBytes(Parameters);
                    webRequest.ContentType = "application/x-www-form-urlencoded";
                    webRequest.ContentLength = byteArray.Length;
                    Stream postStream = webRequest.GetRequestStream();
                    // Add the post data to the web request
                    postStream.Write(byteArray, 0, byteArray.Length);
                    postStream.Close();

                    WebResponse response = webRequest.GetResponse();
                    postStream = response.GetResponseStream();
                    StreamReader reader = new StreamReader(postStream);
                    string responseFromServer = reader.ReadToEnd();

                    GooglePlusAccessToken serStatus = JsonConvert.DeserializeObject<GooglePlusAccessToken>(responseFromServer);

                    if (serStatus != null)
                    {
                        string accessToken = string.Empty;
                        accessToken = serStatus.access_token;

                        if (!string.IsNullOrEmpty(accessToken))
                        {
                            // This is where you want to add the code if login is successful.
                            // getgoogleplususerdataSer(accessToken);
                        }
                    }

                }
            }
        }
        catch (Exception ex)
        {
            //throw new Exception(ex.Message, ex);
            Response.Redirect("index.aspx");
        }
    }
}

现在将调用 google API 的事件

protected void Google_Click(object sender, EventArgs e)
{
     var Googleurl = "https://accounts.google.com/o/oauth2/auth?response_type=code&redirect_uri=" + googleplus_redirect_url + "&scope=https://www.googleapis.com/auth/userinfo.email%20https://www.googleapis.com/auth/userinfo.profile&client_id=" + googleplus_client_id;
     Session["loginWith"] = "google";
     Response.Redirect(Googleurl);
}

添加这个GooglePlusAccessToken class;

// Google
public class GooglePlusAccessToken
{
    public string access_token { get; set; }
    public string token_type { get; set; }
    public int expires_in { get; set; }
    public string id_token { get; set; }
    public string refresh_token { get; set; }
}

也可以拨打其他电话oauth APIAccess Token检索一些用户信息。

private async void getgoogleplususerdataSer(string access_token)
{
    try
    {
        HttpClient client = new HttpClient();
        var urlProfile = "https://www.googleapis.com/oauth2/v1/userinfo?access_token=" + access_token;

        client.CancelPendingRequests();
        HttpResponseMessage output = await client.GetAsync(urlProfile);

        if (output.IsSuccessStatusCode)
        {
            string outputData = await output.Content.ReadAsStringAsync();
            GoogleUserOutputData serStatus = JsonConvert.DeserializeObject<GoogleUserOutputData>(outputData);

            if (serStatus != null)
            {
                 // You will get the user information here.
            }
        }
    }
    catch (Exception ex)
    { 
         //catching the exception
    }
}

public class GoogleUserOutputData
{
    public string id { get; set; }
    public string name { get; set; }
    public string given_name { get; set; }
    public string email { get; set; }
    public string picture { get; set; }
}

希望这就是您正在寻找的,我实现了这个并且运行得很好。 希望这可以帮助。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 C# 使用 Google OAuth 2.0 登录 的相关文章

  • 在实体框架拦截器中向 DbScanExpression 添加内部联接

    我正在尝试使用实体框架 CommandTree 拦截器通过 DbContext 向每个查询添加过滤器 为了简单起见 我有两个表 一个称为 User 有两列 UserId 和 EmailAddress 另一个称为 TenantUser 有两列
  • 何时使用 =default 使析构函数默认?

    尽管对构造函数使用 default 对我来说很清楚 即强制编译器在其他构造函数存在时创建默认构造函数 但我仍然无法理解这两种类型的析构函数之间的区别 那些使用 default 的 那些没有显式定义并由编译器自动生成的 我唯一想到的是 gro
  • 使用 Enumerable.OfType() 或 LINQ 查找特定类型的所有子控件

    Existed MyControl1 Controls OfType
  • VS 程序在调试模式下崩溃,但在发布模式下不崩溃?

    我正在 VS 2012 中运行以下程序来尝试 Thrust 函数查找 include cuda runtime h include device launch parameters h include
  • 与 Qt 项目的静态链接

    我有一个在 Visual Studio 2010 Professional 中构建的 Qt 项目 但是 当我运行它 在调试或发布模式下 时 它会要求一些 Qt dll 如果我提供 dll 并将它们放入 System32 中 它就可以工作 但
  • 如何在 SqlDataReader.Read() 期间从死锁异常中恢复

    我的 NET 应用程序的事件日志显示 它在从 Sql Server 读取数据时偶尔会出现死锁 这种情况通常非常罕见 因为我们已经优化了查询以避免死锁 但有时仍然会发生 过去 我们在调用ExecuteReader函数在我们的SqlComman
  • 找不到 assimp-vc140-mt.dll ASSIMP

    我已经从以下位置下载了 Assimp 项目http assimp sourceforge net main downloads html http assimp sourceforge net main downloads html Ass
  • ASP.Net Core 内容配置附件/内联

    我正在从 WebAPI 控制器返回一个文件 Content Disposition 标头值自动设置为 附件 例如 处置 附件 文件名 30956 pdf 文件名 UTF 8 30956 pdf 当它设置为附件时 浏览器将要求保存文件而不是打
  • 类的成员复制

    在学习 复制成员 概念时 书中给出了如下说法 此外 如果非静态成员是引用 const 或没有复制赋值的用户定义类型 则无法生成默认赋值 我不太明白这个声明到底想传达什么 或者说这个说法指的是哪一种场景 谢谢 该语句与编译器自动为您编写的类
  • vs2008 c#:Facebook.rest.api如何使用它来获取好友列表?

    如何在此基础上取得进一步的进步 获取好友列表的下一步是什么 string APIKey ConfigurationManager AppSettings API Key string APISecret ConfigurationManag
  • 如何在服务器端按钮点击时关闭当前标签页?

    我尝试在确认后关闭当前选项卡 因此我将以下代码放在确认按钮的末尾 但选项卡没有关闭 string jScript ClientScript RegisterClientScriptBlock this GetType keyClientBl
  • 无法在内存位置找到异常源:cudaError_enum

    我正在尝试确定 Microsoft C 异常的来源 test fft exe 中 0x770ab9bc 处的第一次机会异常 Microsoft C 异常 内存位置 0x016cf234 处的 cudaError enum 我的构建环境是 I
  • 如何通过 JsonConvert.DeserializeObject 在动态 JSON 中使用 null 条件运算符

    我正在使用 Newtonsoft 反序列化已知的 JSON 对象并从中检索一些值 如果存在 关键在于对象结构可能会不断变化 因此我使用动态来遍历结构并检索值 由于对象结构不断变化 我使用 null 条件运算符来遍历 JSON 代码看起来像这
  • 每个租户的唯一用户名和电子邮件

    我正在使用以下代码编写多租户应用程序ASP NET Core 2 1 我想覆盖默认的与用户创建相关的验证机制 目前我无法创建多个具有相同的用户UserName My ApplicationUser模型有一个名为TenantID 我想要实现的
  • ASP.NET MailMessage.BodyEncoding 和 MailMessage.SubjectEncoding 默认值

    很简单的问题 但我在 MSDN 上找不到答案 查找 ASP NET 将用于的默认值 MailMessage BodyEncoding and MailMessage SubjectEncoding 如果你不在代码中设置它们 Thanks F
  • 在 EnvDTE 中调试时捕获 VS 局部变量

    是否可以使用 EnvDTE 进行 vsix Visual Studio 扩展来捕获本地和调试窗口使用的调试数据 或者可以通过其他方法吗 我想创建一个自定义的本地窗口 我们可以修改它以根据需要显示一些较重的内容 而无需为高级用户牺牲原始的本地
  • 我可以让 ungetc 取消阻止阻塞的 fgetc 调用吗?

    我想在收到 SIGUSR1 后使用 ungetc 将 A 字符重新填充到标准输入中 想象一下我有充分的理由这样做 调用 foo 时 stdin 中的阻塞读取不会被收到信号时的 ungetc 调用中断 虽然我没想到它会按原样工作 但我想知道是
  • 在简单注入器中解析具有自定义参数的类

    我正在使用以下命令创建 WPF MVVM 应用程序简易注射器作为 DI 容器 现在 当我尝试从简单注入器解析视图时遇到一些问题 因为我需要在构造时将参数传递到构造函数中 而不是在将视图注册到容器时 因此这不是适用的 简单注入器将值传递到构造
  • 将 char[][] 转换为 char** 会导致段错误吗?

    好吧 我的 C 有点生疏了 但我想我应该用 C 来做我的下一个 小 项目 这样我就可以对其进行抛光 并且我已经有不到 20 行的段错误了 这是我的完整代码 define ROWS 4 define COLS 4 char main map
  • Java 和/C++ 在多线程方面的差异

    我读过一些提示 多线程实现很大程度上取决于您正在使用的目标操作系统 操作系统最终提供了多线程能力 比如Linux有POSIX标准实现 而windows32有另一种方式 但我想知道编程语言水平的主要不同 C似乎为同步提供了更多选择 例如互斥锁

随机推荐

  • 阻止 UIScrollView 的子视图调整大小?

    我有一个UIScrollView 具有由返回的视图的多个级别的子视图viewForZoomingInScrollView 在缩放期间 我希望其中一些子视图调整大小 而其他子视图不调整大小 无论我尝试什么 所有子视图都会调整大小 在子视图的超
  • 查询 mongodb 返回今天创建的文档

    我如何编写今天创建的结果文档的过滤器 我知道 ObjectId 有时间戳 我试过这个 db doc find id gte ObjectId getTimestamp getTime 我可以写吗 db doc find id getTime
  • Qml中的QScrollArea:Flickable + QQuickPaintedItem

    我正在尝试实现类似的东西QScrollArea 在小部件世界中 在 Qml 的帮助下 我决定一探究竟Flickable plus QQuickPaintedItem基于项目 在我的例子中名为抽屉 Flickable onContentXCh
  • Rails:backbone-on-rails gem-

    尝试按照 Ryan Bates Backbone js 教程构建抽奖应用程序 但我已经遇到了第一部分代码的问题 在 application js 的 init 函数中 他初始化了 Raffler 路线的新实例 该实例应该触发警报 主页 但我
  • 如何从Java中的Apple公钥JSON响应中获取公钥?

    我们正在尝试在 iOS 应用程序中添加 使用 Apple 登录 当客户端工作正常时 我们的后端是用 Java 编写的 我们无法解码 Apple 的公钥 当您点击网址时https appleid apple com auth keys htt
  • 无法登录 Magento 管理员

    我在登录我们的一个临时站点上的 Magento 管理面板时遇到问题 它在我们的 webdev 服务器上 100 工作 不久前在临时服务器上也工作得很好 我做了一些研究 大多数人认为这与在本地主机上运行 Magento 以及浏览器不为域名中没
  • Lucene:如何在单个字段下索引和搜索多个值

    如何在单个字段下索引和搜索多个值 例如说我有一个领域处理器这可能有i3 i5 i7 or i3 or i3 i5价值观 现在想象一下笔记本电脑的数据如下 data1 name laptop name price laptop price p
  • 接受任意切片的 Express 函数

    我想表达一个可以取任何切片的函数 我想我可以这样做 func myFunc list interface for i range list some other fun i where some other fun 本身需要一个interf
  • 如何将 GMP C 参数约定转换为更自然的东西?

    例如 我想做这样的事情 include
  • 如何使用“prototype”函数正确编写 JavaScript 属性和方法?

    我正在尝试学习如何使用 javascript 原型创建和使用 javascript 属性和方法 但遇到了一些困难 在下面的代码中 我尝试创建一个名为 radius 的简单对象 其半径为 4 并具有一个名为 getCircumference
  • 如果 cookie 未发送到服务器,则可以安全地将访问令牌存储在客户端 cookie 中

    我正在开发一个主干应用程序 其中包含 Laravel 后端的 REST api 这意味着我使用从社交媒体 例如 Facebook Google 等 收到的访问令牌对每个请求进行身份验证 我的计划是存储用 Javascript 生成的客户端
  • Node.js 或 Erlang

    当谈到它们可以处理的并发级别时 我真的很喜欢这些工具 Erlang OTP 看起来是更稳定的解决方案 但需要更多的学习和深入研究函数式语言范例 看起来 Erlang OTP 在多核 CPU 方面做得更好 如果我错了 请纠正我 但我应该选择哪
  • 在 Xcode 4 中本地化 iPhone 应用程序名称

    当我选择 Info plist 文件以便本地化应用程序名称并尝试构建项目时 构建失败并显示错误 提示找不到 Info plist 文件 如果我将 Info plist 文件路径更改为PROJECTNAME en lproj Info pli
  • 如何在 ASP.net MVC 中正确执行异步方法?

    如何从控制器方法内执行异步方法并返回 HttpStatusCodeResult 200 而异步委托不会提前终止其执行 我正在开发一个 asp net 应用程序 我的家庭控制器的一个操作需要很长时间才能运行 10 30 秒 我想返回 Http
  • 求给定数组的每个 (n-1) 个子集的乘积

    很抱歉删除了原来的问题 这里是 我们有一个包含 n 个整数的包或数组 我们需要找到每个 n 1 个子集的乘积 例如 S 1 0 3 6 ps 1 0 3 6 0 ps 2 1 3 6 18 ETC 经过讨论 我们需要处理三种情况 如下所示
  • 交换 javascript 数组中的两个项目[重复]

    这个问题在这里已经有答案了 可能的重复 Javascript 交换数组元素 https stackoverflow com questions 872310 javascript swap array elements 我有一个像这样的数组
  • JQuery Cascade 插件下拉列表不刷新

    我正在使用基于 JQuery 的级联插件 https web archive org web 20111206072619 http plugins jquery com 80 project cascade 可能它有效 但我发现它有很多问
  • 在 Xcode11 Beta 4 中将 String(format: , args) 与 SwiftUI 一起使用时出错

    升级到 Xcode 11 Beta 4 后 我在使用时开始看到错误String format args with State财产 请参阅下面的代码 第二Text行抛出错误 表达式类型 String 在没有更多上下文的情况下不明确 while
  • startAfter 在 Firestore android 中不起作用

    我创建了一个类似测验的应用程序 一次提取 10 个问题 如果用户得到 8 分 满分 10 分 那么我会获取接下来的 10 个问题 但开始之后总是给出相同的回应 val questionCollectionRef db collection
  • 使用 C# 使用 Google OAuth 2.0 登录

    我想允许用户使用登录Gmail 因此 我在 google 上搜索并获得了许多示例 但所有示例都使用 OpenID 而且我检查了 Google 文档 他们已停止 OpenID 的新域注册 从现在开始 开发人员将需要使用 OAuth API 我