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

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)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【算法】动态规划之背包DP问题(2024.5.11)

前言&#xff1a; 本系列是学习了董晓老师所讲的知识点做的笔记 董晓算法的个人空间-董晓算法个人主页-哔哩哔哩视频 (bilibili.com) 动态规划系列 【算法】动态规划之线性DP问题-CSDN博客 01背包 步骤&#xff1a; 分析容量j与w[i]的关系&#xff0c;然后分析是否要放…

iLogtail 社区开源之夏活动来了!

作者&#xff1a;玄飏 在这个充满活力的夏日&#xff0c;随着阳光一同灿烂的是开源精神的光辉与创新的火花。iLogtail 社区高兴地宣布&#xff0c;我们正式加入开源之夏 2024 的行列&#xff0c;诚邀每一位怀揣梦想与激情的学生开发者&#xff0c;共同开启一场探索技术前沿、贡…

WP All Import Pro插件下载 - 一键导入,无限可能

在当今快节奏的数字时代&#xff0c;网站内容的更新和管理是每个网站管理员和开发者的日常工作。但是&#xff0c;传统的手动更新方法不仅耗时&#xff0c;而且容易出错。现在&#xff0c;有了WP All Import Pro&#xff0c;这一切都将改变。 WP All Import Pro 是一款专为Wor…

完美撤离暗区突围测试资格获取指南 超简单的暗区突围资格申请

完美撤离&#xff01;暗区突围测试资格获取指南 超简单的暗区突围资格申请&#xff01; 最近游戏圈关注度最高的一件事莫过于暗区突围国际服的上线&#xff0c;随着暗区突围PC端的上线&#xff0c;这款游戏的测试资格申请成为了玩家们心头的一个大问题&#xff0c;许多玩家爱不…

SpringBoot实现统一返回值+全局异常处理

在这里首先感谢的就是程序员老罗&#xff0c;从他的项目里面学到了这些东西。 首先就是去创建一个SpringBoot项目&#xff0c;这里我就不多做赘述了 封装一个统一返回对象 package com.example.demo.vo;public class ResponseVO<T> {private String status;private In…

YOLOv5-7.0改进(四)添加EMA注意力机制

前言 关于网络中注意力机制的改进有很多种&#xff0c;本篇内容从EMA注意力机制开始&#xff01; 往期回顾 YOLOv5-7.0改进&#xff08;一&#xff09;MobileNetv3替换主干网络 YOLOv5-7.0改进&#xff08;二&#xff09;BiFPN替换Neck网络 YOLOv5-7.0改进&#xff08;三&…

python实现pip一键切换国内镜像源脚本分享

本文主要分享一个自己写的pip一键切换国内镜像源python脚本 import subprocess# pip 国内镜像源加速 source_urls [{"name": "默认镜像源", "url": ""},{"name": "清华大学镜像源(推荐使用)", "url": …

示例十、红外遥控器

通过以下几个示例来具体展开学习,了解红外遥控器原理及特性&#xff0c;学习红外遥控器的应用&#xff08;干货版&#xff09;&#xff1a; 示例十、红外遥控器 ino文件源码&#xff1a; //Arduino C demo #include "IRremote.h"IRrecv irrecv(4); decode_results …

自主实现Telnet流量抓取

自主实现Telnet流量抓取 根据测试需求&#xff0c;需要抓取Telnet流量包&#xff0c;使用wireshark Python&#xff08;socket、telnetlib库&#xff09;实现 实现代码 主要此处有坑&#xff0c; 根据协议规则&#xff0c;wireshark 默认端口为23 的是Telnet协议&#xff0…

递归,搜索,和回溯算法

目录 一、什么是递归&#xff1a; 二、为什么要用到递归 三、如何看待递归这个过程 四、如何写好一个递归 大家也看到了&#xff0c;我们这个算法篇章的开头就比较长&#xff0c;这主要是因为他们三者关系紧密。 一、什么是递归&#xff1a; 我们在学习C语言和数据结构二…

java--io流(二)

一、打印流&#xff08;PrintStream[字节]、PrintWriter[字符]&#xff09; &#xff08;基本上可以代替前面所学的字节、字符输出流&#xff09;&#xff0c;二者关于打印数据功能相同&#xff08;都方便且高效&#xff09;&#xff0c;但是关于数据写出不同&#xff0c;前者…

【算法】并查集

并查集是一种树形的数据结构&#xff0c;通常可以用于高效的合并多个集合和查询两个数是否属于同一个集合的情况。 其原理在于&#xff0c;把每个集合变成一棵树&#xff0c;树根的值就是整个集合的编号&#xff0c;通过查找两个数所在树根是否相同即可判断是否在同一个集合&a…

IDEA 常见设置问题

OutOfMemoryError IDEA 第一次运行项目时&#xff0c;会报错误 - java.lang.OutOfMemoryError: Java heap space / insufficient memory&#xff0c;解决办法是&#xff1a; 将图示部分由默认的 700 改为 2048。 import * 工程lint检查时不允许使用import *&#xff0c;IDE…

容器监控与日志管理

前言&#xff1a;本博客仅作记录学习使用&#xff0c;部分图片出自网络&#xff0c;如有侵犯您的权益&#xff0c;请联系删除 一、Docker监控工具 二、容器日志工具docker logs 三、第三方日志工具 四、容器日志驱动 五、示例 5.1、查看容器中运行的进程的信息 5.2、查看…

小红书·电商运营课:小红书开店流程,小红书电商如何运营(18节视频课)

课程目录 第1节课:学习流程以及后续实操流程注意事项 第2节课:小红书店铺类型解析以及开店细节 第3节课:小红书电商运营两种玩法之多品店铺解析 第4节课:小红书电商运营两种玩法之单品店铺解析 第5节课:选品课(多品类类目推荐) 第6节课:选品课(多品类类目推荐) 第7节课:…

中东电商Noon测评Hepsiburada贺百狮,Souq,Temu,Nice One,MEIG如何自己养号补单?

养买家号进行中东跨境电商测评&#xff0c;是一个需要细心和技术的过程&#xff0c;特别是在不同的电商平台上Noon&#xff08;Namshi&#xff09;、Hepsiburada&#xff08;贺百狮&#xff09;、Souq&#xff08;亚马逊&#xff09;、Nice One、MEIG、Wadi、Temu。需要搭建完整…

严肃处理!光伏巨头被罚2.3亿 | 百能云芯

5月7日&#xff0c;江苏阳光股份有限公司&#xff08;600220 SH&#xff0c;以下简称“ST阳光”&#xff09;公告称&#xff0c;其控股股东江苏阳光集团有限公司&#xff08;以下简称“阳光集团”&#xff09; 近日收到中国证监会《行政处罚事先告知书》&#xff0c;阳光集团涉…

BUU-[极客大挑战 2019]Http

考察点 信息收集 http构造请求数据包 题目 解题步骤 参考文章&#xff1a;https://zhuanlan.zhihu.com/p/367051798 查看源代码 发现有一个a标签&#xff0c;但是οnclick"return false"就是点击后不会去跳转到Secret.php的页面 所以我就自己拼接url http://no…

什么是IP跳变?

IP 跳跃&#xff08;也称为 IP 跳动&#xff09;的概念已引起使用代理访问网站的用户的极大关注。但 IP 跳跃到底是什么&#xff1f;为什么它对于各种在线活动至关重要&#xff1f; 在本文中&#xff0c;我们将深入探讨 IP 跳跃的世界&#xff0c;探索其实际应用、用例、潜在问…

《中阿科技论坛(中英文)》是什么级别的期刊?是正规期刊吗?

问题解答 问&#xff1a;《中阿科技论坛&#xff08;中英文&#xff09;》是核心期刊吗&#xff1f; 答&#xff1a;不是&#xff0c;但是正规期刊 问&#xff1a;《中阿科技论坛&#xff08;中英文&#xff09;》是什么级别期刊&#xff1f; 答&#xff1a;省级 主管单位…