一个基于 C# 开源的第三方 OAuth2 授权登录整合库

前言

在我们的开发工作中有可能会对接过各种各样的第三方平台的登录授权,来获取用户的相关账号信息(如:微信登录、支付宝登录、飞书登录、钉钉登录、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推荐或自荐(让优秀的项目和框架不被埋没🤞)。

posted @   追逐时光者  阅读(600)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 2分钟学会 DeepSeek API,竟然比官方更好用!
· .NET 使用 DeepSeek R1 开发智能 AI 客户端
· 10亿数据,如何做迁移?
· 推荐几款开源且免费的 .NET MAUI 组件库
· c# 半导体/led行业 晶圆片WaferMap实现 map图实现入门篇
历史上的今天:
2024-02-06 .NET中使用BootstrapBlazor组件库Table实操篇
点击右上角即可分享
微信分享提示