一个基于 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推荐或自荐(让优秀的项目和框架不被埋没🤞)。

相关推荐
追逐时光者23 天前
C#/.NET/.NET Core技术前沿周刊 | 第 62 期(2025年11.17-11.23)
【.net】·【c#】·【技术前沿周刊】
追逐时光者1 个月前
快速构建一个基础、现代化的 WinForm 管理系统!
【.net】·【开源项目】·【winform】
追逐时光者1 个月前
C#/.NET/.NET Core技术前沿周刊 | 第 61 期(2025年11.10-11.16)
【.net】·【技术前沿周刊】
追逐时光者1 个月前
好消息,.NET 10 正式发布,更智能、更安全、更高性能的统一开发平台!
【.net】·【c#】