ASP.NET WebApi 如何使用 OAuth2.0 认证

news2024/11/17 7:24:29

image

前言

OAuth 2.0 是一种开放标准的授权框架,用于授权第三方应用程序访问受保护资源的流程。

OAuth 2.0 认证是指在这个框架下进行的身份验证和授权过程。

在 OAuth 2.0 认证中,涉及以下主要参与方:

  1. 资源所有者(Resource Owner): 拥有受保护资源的用户。
  2. 客户端(Client): 第三方应用程序,希望访问资源所有者的受保护资源。
  3. 授权服务器(Authorization Server): 负责验证资源所有者的身份并颁发访问令牌。
  4. 资源服务器(Resource Server): 存储受保护资源的服务器,用于接收和响应客户端请求。

OAuth 2.0 认证的流程通常包括以下步骤:

  1. 客户端注册: 客户端向授权服务器注册,并获得客户端标识和客户端密钥。
  2. 请求授权: 客户端向资源所有者请求授权,以获取访问受保护资源的权限。
  3. 授权许可: 资源所有者同意授权,授权服务器颁发授权码给客户端。
  4. 获取访问令牌: 客户端使用授权码向授权服务器请求访问令牌。
  5. 访问受保护资源: 客户端使用访问令牌向资源服务器请求访问受保护资源。

OAuth 2.0 认证的优势在于可以实现用户授权而无需透露密码,同时提供了更安全和灵活的授权机制,更好地保护用户数据和系统安全。

以下是一个 ASP.NET WebApi 简单使用 OAuth2.0 认证的 Step By Step 例子。

Step By Step 步骤

  1. 新建一个空 ASP.NET WebApi 项目,比如 TokenExample

  2. 在 Models 目录下新建一个 Product 实体类:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    
    namespace TokenExample.Models
    {
    	public class Product
    	{
    		public int Id { get; set; }
    		public string Name { get; set; }
    		public string Category { get; set; }
    		public decimal Price { get; set; }
    	}
    }
    
  3. 在 Controllers 目录下新建一个 ProductsController 控制器

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Net.Http;
    using System.Web.Http;
    using TokenExample.Models;
    
    namespace TokenExample.Controllers
    {
    	public class ProductsController : ApiController
    	{
    		// 初始化数据
    		Product[] products = new Product[]
    		{
    			new Product { Id = 1, Name = "Tomato Soup", Category = "Groceries", Price = 1 },
    			new Product { Id = 2, Name = "Yo-yo", Category = "Toys", Price = 3.75M },
    			new Product { Id = 3, Name = "Hammer", Category = "Hardware", Price = 16.99M }
    		};
    
    		// 查找所有的产品
    		public IEnumerable<Product> GetAllProducts()
    		{
    			return products;
    		}
    
    		// 根据 id 查找产品
    		public Product GetProductById(int id)
    		{
    			var product = products.FirstOrDefault((p) => p.Id == id);
    			if (product == null)
    			{
    				throw new HttpResponseException(HttpStatusCode.NotFound);
    			}
    			return product;
    		}
    		
    		// 根据 类别 查找产品
    		public IEnumerable<Product> GetProductsByCategory(string category)
    		{
    			return products.Where(p => string.Equals(p.Category, category, StringComparison.OrdinalIgnoreCase));
    		}
    	}
    }
    
  4. 将网站部署到 IIS, 端口为 8080,使用 Postman 工具测试以下 api:

    GET http://localhost:8080/api/Products
    GET http://localhost:8080/api/Products/1
    GET http://localhost:8080/api/Products?category=Groceries
    

    可以看到这些 API 都是可以公开访问的,没有任何验证

  5. 在 WebApi 项目右键,选择 “管理 Nuget 程序包”,打开 Nuget 包管理器 GUI, 安装以下包:

    Microsoft.AspNet.WebApi.Owin
    Microsoft.Owin.Host.SystemWeb
    Microsoft.AspNet.Identity.Owin
    Microsoft.Owin.Cors
    EntityFramework

  6. 在项目根目录下添加 “Startup” 类, 这是 Owin 的启动类(注意是项目根目录,即跟 Global.asax 同一位置)

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Http;
    using Owin;
    using Microsoft.Owin;
    using Microsoft.Owin.Security.OAuth;
    
    [assembly: OwinStartup(typeof(TokenExample.Startup))]
    namespace TokenExample
    {
    	public class Startup
    	{
    		public void Configuration(IAppBuilder app)
    		{
    			HttpConfiguration config = new HttpConfiguration();
    			ConfigureOAuth(app);
    
    			WebApiConfig.Register(config);
    			app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
    			app.UseWebApi(config);
    		}
    
    		public void ConfigureOAuth(IAppBuilder app)
    		{
    			OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
    			{
    				AllowInsecureHttp = true,
    				// 这里设置获取 token 有 url path
    				TokenEndpointPath = new PathString("/token"),
    				AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
    				Provider = new SimpleAuthorizationServerProvider()
    			};
    			app.UseOAuthAuthorizationServer(OAuthServerOptions);
    			app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
    		}
    	}
    }
    
  7. 删除 Global.asax

    • NOTE: 设置了 Startup 类, 就不需要 Global.asax 了,可以删除,也可以留着
  8. 在项目根目录下添加验证类 SimpleAuthorizationServerProvider

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    
    using System.Threading;
    using System.Threading.Tasks;
    using Microsoft.Owin;
    using Microsoft.Owin.Security.OAuth;
    using System.Security.Claims;
    
    namespace TokenExample
    {
    	public class SimpleAuthorizationServerProvider: OAuthAuthorizationServerProvider
    	{
    		public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
    		{
    			context.Validated();
    		}
    
    		public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    		{
    			// 设置允许跨域
    			context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
    
    			/*
    			 * 对用户名、密码进行数据校验,这里我们省略
    			using (AuthRepository _repo = new AuthRepository())
    			{
    				IdentityUser user = await _repo.FindUser(context.UserName, context.Password);
    
    				if (user == null)
    				{
    					context.SetError("invalid_grant", "The user name or password is incorrect.");
    					return;
    				}
    			}
    			*/
    
    			var identity = new ClaimsIdentity(context.Options.AuthenticationType);
    			identity.AddClaim(new Claim("sub", context.UserName));
    			identity.AddClaim(new Claim("role", "user"));
    
    			context.Validated(identity);
    		}
    	}
    }
    
  9. 修改 ProductsController 类,在 Action 上增加 [Authorize] 特性,代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Net.Http;
    using System.Web.Http;
    using TokenExample.Models;
    
    namespace TokenExample.Controllers
    {
    	public class ProductsController : ApiController
    	{
    		Product[] products = new Product[]
    		{
    			new Product { Id = 1, Name = "Tomato Soup", Category = "Groceries", Price = 1 },
    			new Product { Id = 2, Name = "Yo-yo", Category = "Toys", Price = 3.75M },
    			new Product { Id = 3, Name = "Hammer", Category = "Hardware", Price = 16.99M }
    		};
    
    		// [Authorize] 特性是启用 OAuth 的 Access Token 验证,让 CORS 起作用
    		[Authorize]
    		public IEnumerable<Product> GetAllProducts()
    		{
    			return products;
    		}
    
    		[Authorize]
    		public Product GetProductById(int id)
    		{
    			var product = products.FirstOrDefault((p) => p.Id == id);
    			if (product == null)
    			{
    				throw new HttpResponseException(HttpStatusCode.NotFound);
    			}
    			return product;
    		}
    
    		// [AllowAnonymous] 特性是允许匿名访问,即无需 Access Token 验证
    		[AllowAnonymous]
    		public IEnumerable<Product> GetProductsByCategory(string category)
    		{
    			return products.Where(p => string.Equals(p.Category, category, StringComparison.OrdinalIgnoreCase));
    		}
    	}
    }
    

测试

  1. 重新在 Postman 运行以下命令:

    GET http://localhost:8080/api/Products
    返回:
    {
    	"Message": "已拒绝为此请求授权。"
    }
    这是预期的
    
  2. 在 Postman 运行以下命令:

    POST/GET http://localhost:23477/token
    参数 BODY x-www-form-urlencoded 格式:
    grant_type=password
    username=admin 
    password=123456
    
    返回:
    {
    	"access_token": "ESWxgOCWDDPBRg37cX2RIAb8h--AYgz55rheYumSEU9YVjikYowyih1EdkVUg5vEeuLEeuhZPFJFGe33N3yvieYCzVQ2r0FKYBj0vydKnHAZ7CpLry4DaOhZ8JKIxa159QiBZubA_YgtFliUggSefiosrXW-FaUUO-m5th4YwInw2_5aGPL73uB5FYE0LcLN51U8ZlqoeLDChO3MdTigTc90rVUNiiZ3UBHn-HWvSnI",
    	"token_type": "bearer",
    	"expires_in": 86399
    }
    
  3. 在以下 api 的 Headers 加上:

    GET http://localhost:8080/api/Products
    Headers
    Key: Authorization
    Value: bearer ESWxgOCWDDPBRg37cX2RIAb8h--AYgz55rheYumSEU9YVjikYowyih1EdkVUg5vEeuLEeuhZPFJFGe33N3yvieYCzVQ2r0FKYBj0vydKnHAZ7CpLry4DaOhZ8JKIxa159QiBZubA_YgtFliUggSefiosrXW-FaUUO-m5th4YwInw2_5aGPL73uB5FYE0LcLN51U8ZlqoeLDChO3MdTigTc90rVUNiiZ3UBHn-HWvSnI
    
  4. 重新运行,即可正常访问,至此就完成了简单的 ASP.NET WebApi 使用 OAuth2.0 认证

总结

  1. OAuth2.0 有 Client 和 Scope 的概念,JWT 没有,如果只是拿来用于颁布 Token 的话,二者没区别,如本例
  2. OAuth2.0 和 JWT 在使用 Token 进行身份验证时有相似之处,但实际上它们是完全不同的两种东西,OAuth2.0 是授权认证的框架,JWT 则是认证验证的方式方法(轻量级概念)
  3. OAuth2.0 更多用在使用第三方账号登录的情况(比如使用 weibo,qq,github 等登录某个 app)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1664660.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Agisoft Metashape Pro for Mac/win:开启三维建模新视界

在当今数字化的时代&#xff0c;三维建模技术正发挥着越来越重要的作用。而 Agisoft Metashape Pro for Mac/win 无疑是该领域的一颗璀璨明星。 这款强大的三维建模软件为专业人士和爱好者提供了无与伦比的工具和功能。无论你是从事建筑设计、考古研究、影视特效制作还是地理信…

【nodejs 命令行交互神器 - inquirer.js】

需求 大家在开发时&#xff0c;有时需要从命令行读取用户的输入&#xff0c;或者让用户选择。在nodejs中&#xff0c;这个怎么实现? 原生实现 ❌ process.stdin.setEncoding(utf8);process.stdin.on(readable, () > {let chunk;// 使用循环确保我们读取所有的可用输入wh…

导电材料——分类、性能与性质

本篇为西安交通大学本科课程《电气材料基础》的笔记。 导电材料指的是能在电场下传导电流的材料。导体价电子所在能带为半满带&#xff0c;且相邻能级间隔小&#xff0c;外电场下电子很容易从低能级跃迁到高能级上&#xff0c;大量的电子很容易获得能量进行共有化运动&#xf…

winhex工具,将文件转换为16进制数据放入代码。

今天介绍winhex工具&#xff0c;可以将任何内容读取读取为16进制数据。下面看下效果。 下载链接&#xff1a; WinHex: Hex Editor & Disk Editor, Computer Forensics & Data Recovery Software 一、WinHex打开文件 我们要打开的文件&#xff1a; 打开后&#xff1a; 我…

QueryPerformanceCounter实现高精度uS(微妙)延时

参考连接 C# 利用Kernel32的QueryPerformanceCounter封装的 高精度定时器Timer_kernel32.dll queryperformancecounter-CSDN博客https://blog.csdn.net/wuyuander/article/details/111831973 特此记录 anlog 2024年5月11日

ubuntu系统在有无NVIDIA驱动下查看显卡型号

在ubuntu系统下&#xff0c;分别在有nvidia显卡驱动和无nvidia显卡驱动时&#xff0c;查看nvidia显卡型号。 1、有nvidia显卡驱动时的查看方式 nvidia-smi -L会显示如下信息&#xff1a; GPU 0: NVIDIA GEForce GTX 1660 SUPER (UUID: GPU-*****)2、无nvidia显卡驱动时的查看…

凸优化理论学习一|最优化及凸集的基本概念

文章目录 一、优化问题&#xff08;一&#xff09;数学优化&#xff08;二&#xff09;凸优化 二、凸集&#xff08;一&#xff09;一些标准凸集&#xff08;二&#xff09;保留凸性的运算&#xff08;三&#xff09;正常锥和广义不等式&#xff08;四&#xff09;分离和支撑超…

TriDet: Temporal Action Detection with Relative Boundary Modeling

标题&#xff1a;TriDet&#xff1a;采用相对边界建模的时间动作检测 原文链接&#xff1a;TriDet: Temporal Action Detection With Relative Boundary Modeling (thecvf.com)https://openaccess.thecvf.com/content/CVPR2023/papers/Shi_TriDet_Temporal_Action_Detection_W…

SpringBoot @DS注解 和 DynamicDataSource自定义实现多数据源的2种实现方式

前言 在实际的项目中&#xff0c;我们经常会遇到需要操作多个数据源的情况&#xff0c;SpringBoot为我们提供了多种实现多数据源的方式。本文将介绍两种常见的方式&#xff1a;使用DS注解实现多数据源的切换以及使用DynamicDataSource自定义实现多数据源的切换。 我们将分别介…

土地档案管理关系参考论文(论文 + 源码)

【免费】javaEE土地档案管理系统.zip资源-CSDN文库https://download.csdn.net/download/JW_559/89296786 土地档案管理关系 摘 要 研究土地档案管理关系即为实现一个土地档案管理系统。土地档案管理系统是将现有的历史纸质档案资料进行数字化加工处理&#xff0c;建成标准化的…

boost asio同步编程(附源码api)

首先注明&#xff0c;这里我写的都是关于tcp的通信。 通信大致流程 创建端点 创建tcp端点的api是boost::asio::ip::tcp::endpoint; 当然创建udp端点的api则是boost::asio::ip::udp::endpoint; 是一个表示 TCP/UDP 端点的类&#xff0c;在 Boost.Asio 库中用于网络编程。它通…

工业机器人应用实践之玻璃涂胶(篇三)

工业机器人 接上篇文章&#xff0c;浅谈一下实践应用&#xff0c;具体以玻璃涂胶为例&#xff1a; 了解工业机器人在玻璃涂胶领域的应用 认识工具坐标系的标定方法 掌握计时指令的应用 掌握人机交互指令的应用 掌握等待类指令用法&#xff08;WaitDI、WaitUnitl 等&#xff0…

正点原子Linux学习笔记(九)在 LCD 上显示字符

在 LCD 上显示字符 23.1 原始方式&#xff1a;取模显示字符23.2 freetype 简介23.3 freetype 移植下载 FreeType 源码交叉编译 FreeType 源码安装目录下的文件移植到开发板 23.4 freetype 库的使用初始化 FreeType 库加载 face 对象设置字体大小加载字形图像 23.5 示例代码 前面…

再谈毕业论文设计投机取巧之IVR自动语音服务系统设计(信息与通信工程A+其实不难)

目录 举个IVR例子格局打开&#xff0c;万物皆能IVR IVR系统其实可盐可甜。还能可圈可点。 戎马一生&#xff0c;归来依然IVR。 举个IVR例子 以下是IVR系统的一个例子。 当您拨打电话进入IVR系统。 首先检验是否为工作时间。 如是&#xff0c;您将被送入ivr-lang阶段&#xff0…

【Delphi 爬虫库 6】使用正则表达式提取猫眼电影排行榜top100

正则表达式库的简单介绍 正则表达式易于使用&#xff0c;功能强大&#xff0c;可用于复杂的搜索和替换以及基于模板的文本检查。这对于输入形式的用户输入验证特别有用-验证电子邮件地址等。您还可以从网页或文档中提取电话号码&#xff0c;邮政编码等&#xff0c;在日志文件中…

机器学习算法应用——CART决策树

CART决策树&#xff08;4-2&#xff09; CART&#xff08;Classification and Regression Trees&#xff09;决策树是一种常用的机器学习算法&#xff0c;它既可以用于分类问题&#xff0c;也可以用于回归问题。CART决策树的主要原理是通过递归地将数据集划分为两个子集来构建决…

在 Kubernetes 上运行 Apache Spark 进行大规模数据处理的实践

在刚刚结束的 Kubernetes Community Day 上海站&#xff0c;亚马逊云科技在云原生分论坛分享的“在 Kunernets 上运行 Apache Spark 进行大规模数据处理实践”引起了现场参与者的关注。开发者告诉我们&#xff0c;为了充分利用 Kubernetes 的高可用设计、弹性&#xff0c;在越来…

Leedcode题目:移除链表元素

题目&#xff1a; 这个题目就是要我们将我们的链表中的值是val的节点删除。 我们题目提供的接口是 传入了指向一个链表的第一个节点的指针&#xff0c;和我们要删除的元素的值val&#xff0c;不只要删除第一个&#xff0c; 思路 我们这里可以创建一个新的链表&#xff0c;…

配置Docker对象与管理守护进程

前言&#xff1a;本博客仅作记录学习使用&#xff0c;部分图片出自网络&#xff0c;如有侵犯您的权益&#xff0c;请联系删除 本章节的快速目录导航&#xff1a; 一、配置Docker对象 1.1、Docker对象的标记 1.2、格式化命令和日志的输出 二、示例&#xff1a; 2.1、管理…

HTML【常用的标签】、CSS【选择器】

day45 HTML 继day44&#xff0c;w3cschool 常用的标签 k) 表格 表格由 table 标签来定义。每个表格均有若干行&#xff08;由 tr 标签定义&#xff09;&#xff0c;每行被分割为若干单元格&#xff08;由 标签定义&#xff09;。字母 td指表格数据&#xff08;table data&…