前言

在我们的开发工作中有可能会对接过各种各样的第三方平台的登录授权,来获取用户的相关账号信息(如:微信登录、支付宝登录、飞书登录、钉钉登录、GitHub登录等等)。今天大姚给大家推荐一个基于 C# 开源的第三方 OAuth2 授权登录整合库:Netnr.Login。

项目介绍

Netnr.Login是一个基于 C# 开源(MIT License)的第三方 OAuth2 授权登录整合库,集成了QQ、微信开放平台(Weixin)、微信公众平台(WeixinMP)、微博(Weibo)、淘宝(Taobao)、支付宝(Alipay)、钉钉(DingTalk)、飞书(Feishu)、华为(Huawei)、小米(Xiaomi)、AtomGit、码云(Gitee)、GitHub、GitLab、微软(Microsoft )、StackOverflow等授权登录功能,可以帮助大家快速完成常见的第三方平台的登录授权功能。

支持第三方登录

项目源码

快速接入

使用说明

        /// <summary>
        /// 说明
        /// </summary>
        /// <returns></returns>
        public IActionResult Index()
        {
            /*
                LoginTo.EntryOfStep<TBefore, TReq>(LoginWhich, LoginStep, Func<string, string> stateCall)
                每个步骤入口,接收5个参数:LoginWhich、LoginStep、TBefore、TReq、stateCall

                LoginWhich 哪家,枚举对象,如 QQ GitHub 等
                LoginStep 步骤,枚举对象,顺序 Authorize(跳转授权链接)、AccessToken(根据授权码 code 请求令牌)、RefreshToken(刷新令牌,可选)、OpenId(仅QQ)、User(用户信息,不支持Taobao)

                TBefore 之前的结果(上一步返回的结果,用于自动生成请求对象 TReq)
                TReq 请求对象,自定义构建请求参数,传值则不从 TBefore 构建,两者二选一

                stateCall 步骤为 Authorize 构建授权链接 state 字段回调方法

                请求参数类名遵循 LoginWhich + LoginStep + Model
                如 GitHub Authorize Model => GitHub AccessToken Model => GitHub User Model

                AuthorizeResult 为统一接收授权码对象,其它步骤返回的对象均为 DocModel
                DocModel 对象中 Raw 为原始结果字符串,Doc 为 System.Text.Json 组件下的仅读对象            
             */

            return Ok();
        }

三方登录并跳转授权页面

        /// <summary>
        /// 三方登录并跳转授权页面
        /// </summary>
        /// <param name="id">哪家</param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult Auth([FromRoute] LoginWhich? id)
        {
            AssignKey();

            if (id.HasValue)
            {
                var loginType = id.Value;

                //默认构建请求链接
                DocModel authResult = LoginTo.EntryOfStep<object, object>(loginType, LoginStep.Authorize, stateCall: (state) => $"login_{state}");
                if (!string.IsNullOrEmpty(authResult.Raw))
                {
                    return Redirect(authResult.Raw);
                }

                //或 自定义构建请求链接
                authResult = LoginTo.EntryOfStep<object, QQAuthorizeModel>(loginType, LoginStep.Authorize, reqModel: new()
                {
                    State = $"bind_{DateTime.Now:yyyyMMddHHmmss}"
                });
                Console.WriteLine(authResult.Raw);
            }

            return BadRequest();
        }

三方登录回调

        /// <summary>
        /// 三方登录回调
        /// </summary>
        /// <param name="id">哪家</param>
        /// <param name="authResult">接收授权码</param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult AuthCallback([FromRoute] LoginWhich id, AuthorizeResult authResult)
        {
            //极简拿到最终用户信息
            var publicUser = LoginTo.Entry(id, authResult);

            var result = publicUser.ToJson(true);
            Console.WriteLine(result);

            return Ok(result);
        }

        /// <summary>
        /// 三方登录回调,所有步骤的信息
        /// </summary>
        /// <param name="id">哪家</param>
        /// <param name="authResult">接收授权码</param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult AuthCallback_Steps([FromRoute] LoginWhich id, AuthorizeResult authResult)
        {
            //含步骤信息
            (DocModel tokenResult, DocModel openidResult, DocModel userResult, PublicUserResult publicUser) = LoginTo.EntryOfSteps(id, authResult);

            var result = new
            {
                tokenResult,
                openidResult,
                userResult,
                publicUser
            }.ToJson(true);
            Console.WriteLine(result);

            return Ok(result);
        }

        /// <summary>
        /// 三方登录回调,逐步
        /// </summary>
        /// <param name="id">哪家</param>
        /// <param name="authResult">接收授权码</param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult AuthCallback_Step([FromRoute] LoginWhich? id, AuthorizeResult authResult)
        {
            try
            {
                if (id == null)
                {
                    throw new Exception($"不支持该方式授权 {RouteData.Values["id"]?.ToString()}");
                }
                else if (authResult.NoAuthCode())
                {
                    throw new Exception($"授权失败");
                }
                else
                {
                    var loginType = id.Value;
                    Console.WriteLine($"{Environment.NewLine}----- Sign in with {loginType} {DateTime.Now:yyyy-MM-dd HH:mm:ss}{Environment.NewLine}");

                    //step: access token(非 旧版 DingTalk)
                    DocModel tokenResult = null;
                    //step: openid (仅 QQ)
                    DocModel openidResult = null;
                    //step: user (非 Taobao)
                    DocModel userResult = null;

                    if (!(loginType == LoginWhich.DingTalk && DingTalk.IsOld))
                    {
                        tokenResult = LoginTo.EntryOfStep<AuthorizeResult, object>(loginType, LoginStep.AccessToken, beforeResult: authResult);
                        Console.WriteLine($"{Environment.NewLine}{nameof(LoginStep.AccessToken)}");
                        Console.WriteLine(tokenResult.Doc.ToJson(true));

                        //step: refresh token (可选,仅支持部分)
                        if (!new[] { LoginWhich.Weibo, LoginWhich.Taobao, LoginWhich.GitHub, LoginWhich.StackOverflow }.Contains(loginType)
                            && !(loginType == LoginWhich.Microsoft && Login.Microsoft.IsOld))
                        {
                            tokenResult = LoginTo.EntryOfStep<DocModel, object>(loginType, LoginStep.RefreshToken, beforeResult: tokenResult);
                            Console.WriteLine($"{Environment.NewLine}{nameof(LoginStep.RefreshToken)}");
                            Console.WriteLine(tokenResult.Doc.ToJson(true));
                        }
                    }
                    if (loginType == LoginWhich.QQ)
                    {
                        openidResult = LoginTo.EntryOfStep<DocModel, object>(loginType, LoginStep.OpenId, beforeResult: tokenResult);
                        userResult = LoginTo.EntryOfStep<DocModel[], object>(loginType, LoginStep.User, beforeResult: [tokenResult, openidResult]);
                    }
                    else if (loginType == LoginWhich.DingTalk && DingTalk.IsOld)
                    {
                        userResult = LoginTo.EntryOfStep<object, AuthorizeResult>(loginType, LoginStep.User, reqModel: authResult);
                    }
                    else if (loginType != LoginWhich.Taobao)
                    {
                        userResult = LoginTo.EntryOfStep<DocModel, object>(loginType, LoginStep.User, beforeResult: tokenResult);
                    }

                    if (openidResult != null)
                    {
                        Console.WriteLine($"{Environment.NewLine}{nameof(LoginStep.OpenId)}");
                        Console.WriteLine(openidResult.Doc.ToJson(true));
                    }
                    if (userResult != null)
                    {
                        Console.WriteLine($"{Environment.NewLine}{nameof(LoginStep.User)}");
                        Console.WriteLine(userResult.Doc.ToJson(true));
                    }

                    return Ok("Done!");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                return BadRequest($"授权失败 {ex.Message}");
            }
        }

        /// <summary>
        /// 三方登录回调,自定义构建请求参数
        /// </summary>
        /// <param name="code">接收授权码</param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult AuthCallback_GitHub(string code)
        {
            //step: access token
            DocModel tokenResult = LoginTo.EntryOfStep<object, GitHubAccessTokenModel>(LoginWhich.GitHub, LoginStep.AccessToken, reqModel: new GitHubAccessTokenModel()
            {
                Code = code
            });
            Console.WriteLine(tokenResult.Doc.ToJson(true));

            //step: user
            DocModel userResult = LoginTo.EntryOfStep<object, GitHubUserModel>(LoginWhich.GitHub, LoginStep.User, reqModel: new GitHubUserModel()
            {
                Access_Token = tokenResult.Doc.GetValue("access_token")
            });

            Console.WriteLine(userResult.Doc.ToJson(true));

            return Content(userResult.Raw);
        }

项目源码地址

更多项目实用功能和特性欢迎前往项目开源地址查看,别忘了给项目一个Star支持。

优秀项目和框架精选

该项目已收录到C#/.NET/.NET Core优秀项目和框架精选中,关注优秀项目和框架精选能让你及时了解C#、.NET和.NET Core领域的最新动态和最佳实践,提高开发工作效率和质量。坑已挖,欢迎大家踊跃提交PR推荐或自荐(让优秀的项目和框架不被埋没)。

一个基于 C# 开源的第三方 OAuth2 授权登录整合库的更多相关文章

  1. 第三方OAuth授权登录,QQ、微信(WeChat)、微博、GitHub、码云(Gitee)、淘宝(天猫)、微软(Microsoft )、钉钉、谷歌(Google)、支付宝(AliPay)、StackOverflow

    Netnr.Login 第三方OAuth授权登录 支持第三方登录 三方 参考文档 参考文档 参考文档 参考文档 参考文档 参考文档 参考文档 参考文档 参考文档 参考文档 参考文档 参考文档 安装 ( ...

  2. 基于第三方微信授权登录的iOS代码分析

    本文转载至 http://www.cocoachina.com/ios/20140922/9715.html 微信已经深入到每一个APP的缝隙,最常用的莫过分享和登录了,接下来就以代码的形式来展开微信 ...

  3. 解决微信公众号授权登录和开放平台微信第三方应用授权登录获取到的用户Openid关联问题

    开发背景: 最近一段时间一直在做关于微信方面的网站应用开发,这段时间也收获的不少关于微信开发方面的开发技能,接触的比较多的主要有微信公众号和微信网站app第三方登录授权,以及微信会员卡,优惠券和扫描二 ...

  4. iOS 基于第三方QQ授权登录

    基于iOS实现APP的第三方QQ登陆.接入第三方SDK时的一个主要的步骤: 1,找到相关的开放平台.QQ互联平台,http://connect.qq.com/: 2,注冊成功后创建自己的APP.填写一 ...

  5. AbpZero之企业微信---登录(拓展第三方auth授权登录)---第二步:开始逐步实现企业微信登录

    上回分解到AbpZero的auth登录机制,这里我们开始着手逐步实现我们的auth登录. 我们新建一个类库XXXX.Web.Authentication.External 在类库下新建一个类QYWec ...

  6. 发布一个基于协程和事件循环的c++网络库

    目录 介绍 使用 性能 实现 日志库 协程 协程调度 定时器 Hook RPC实现 项目地址:https://github.com/gatsbyd/melon 介绍 开发服务端程序的一个基本任务是处理 ...

  7. Yoshino: 一个基于React的可定制化的PC组件库

    Github: https://github.com/Yoshino-UI... Docs: https://yoshino-ui.github.io/#/ Cli-Tool: https://git ...

  8. 一个基于Unix套接字的注册登录系统

    2016/5/5 今天,我参考<Unix网络编程-卷1>第5章的TCP回射客户/服务器程序写了一个简单的注册登录系统,其功能如下:(1)注册.客户端向服务器发送个人信息请求注册,服务器查询 ...

  9. AbpZero之企业微信---登录(拓展第三方auth授权登录)---第三步:需要注意事项

    1.AbpZero的auth登录会在数据库中的AbpUserLogins表会根据你登录的ProviderKey和Provider来生成生成一条记录,ProviderKey在表中是唯一的: 2.要登录成 ...

  10. AbpZero之企业微信---登录(拓展第三方auth授权登录)---第一步:查看AbpZero的auth第三方登录的底层机制

    在AbpZero框架中,auth登录接口位于Web.Core库下的Controllers文件夹的TokenAuthController.cs的ExternalAuthenticate方法 Extern ...

随机推荐

  1. linux 查看进程的bin文件所在路径

    1.获取进程pid ps aux |grep nginx|grep master|grep -v grep|awk '{print $2}' 2.根据进程pid 获取 bin路径 方法a pwdx p ...

  2. pycharm里的jinja2注释问题

    pycharm里html注释是{# #}而不是<!-- -->?   修改方式:如图修改成值None以后,command+/快捷键,html注释的符号就是<!-- 注释内容 --&g ...

  3. Educational Codeforces Round 105 (Rated for Div

    Educational Codeforces Round 105 (Rated for Div. 2) ABC String 给定一个字符串只有A.B和C构成.要求替换A.B.C为')'和'(',并且 ...

  4. Konva.js

    1.前言 简介:Konva.js - 适用于桌面/移动端应用的 HTML5 2d canvas 库 个人体验:原生的canvas只支持绘制基本的直线,矩形,文字,图片,扇形等,如果要支持更复杂的功能, ...

  5. 如何在 Epicor 中计算绩效

    制造性能是任何生产工序的关键,允许企业衡量和评估其效率和生产力水平. 我们将探讨如何在 Epicor 中计算制造性能.计算整体设备效率(OEE) 时性能指标的价值.如何解释制造指标以及在 Epicor ...

  6. 生产环境BigDecimal用错了,已哭晕在厕所。。。

    大家好,我是苏三,又跟大家见面了. 前言 在日常开发中,很多小伙伴喜欢用 BigDecimal 来处理精确计算,比如钱.分数.比例啥的. 理论上,它比 double 或 float 更精确,但如果你用 ...

  7. StarBlog博客Vue前端开发笔记:(2)页面路由

    前言 Vue.js 使用虚拟 DOM 处理单页面,然后使用 Webpack 打包.通过上一篇文章的例子,读者也许已经发现,无论语法和写法如何不同,Vue.js 程序打包后都是一个单一的 HTML 文件 ...

  8. js 吸顶以及一些获取文档高度等小方法

    1.返回html文档元素document.documentElement 2.文档的高度document.body.clientHeight 3.html文档可视高度==页面可见区域的高度docume ...

  9. 解决用netty去做web服务时,post长度过大的问题

    原文地址 http://my.oschina.net/momohuang/blog/114552 先说一下,本来是想自己写socket ,启动一个简单点的web服务用于接收数据的.写完之后,发现会有各 ...

  10. Springboot使用mongodb遇到问题及解决

    网上看到使用mongodb好像很简单,没有什么问题,可我一用就怎么都连不上,先看看我的配置 在pom.xml中添加依赖 1234 <dependency>    <groupId&g ...