ASP.NET Web API 2基于令牌的身份验证
基于令牌的认证
我们知道WEB网站的身份验证一般通过session或者cookie完成的,登录成功后客户端发送的任何请求都带上cookie,服务端根据客户端发送来的cookie来识别用户。
WEB API使用这样的方法不是很适合,于是就有了基于令牌的认证,使用令牌认证有几个好处:可扩展性、松散耦合、移动终端调用比较简单等等,别人都用上了,你还有理由不用吗?
下面我们花个20分钟的时间来实现一个简单的WEB API token认证:
Step 1: 新建一个空的WEB API项目,项目名称就设置为WebApi
Step 2: 在Models目录下新建一个 Product 类 :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web; namespace WebApi.Models
{
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public string Category { get; set; }
public decimal Price { get; set; }
}
}
Step 3:在Controllers目录下新建一个 ProductsController 类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web.Http; using WebApi.Models; namespace WebApi.Controllers
{
[RoutePrefix("api/Products")]
public class ProductsController : ApiController
{
Product[] products = new Product[]
{
new Product { Id = , Name = "Tomato Soup", Category = "Groceries", Price = },
new Product { Id = , Name = "Yo-yo", Category = "Toys", Price = 3.75M },
new Product { Id = , Name = "Hammer", Category = "Hardware", Price = 16.99M }
}; public IEnumerable<Product> GetAllProducts()
{
return products;
} 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));
}
}
}
F5运行后就可以使用这个简单的WebApi了,测试api可以使用Postman工具:
获取所有数据 http://localhost:1234/api/products
获取内码为1的数据 http://localhost:1234/api/products/1
查询category=的数据 http://localhost:1234/api/products?category=Groceries
可以看到这个产品的API是公开访问的,没有任何验证,这样不是很安全,下一步我将加上token验证。
Step 4:安装所需的NuGet包:
打开NuGet包管理器控制台,然后输入如下指令:
Install-Package Microsoft.AspNet.WebApi.Owin -Version 5.1.
Install-Package Microsoft.Owin.Host.SystemWeb -Version 2.1.
Install-Package Microsoft.AspNet.Identity.Owin -Version 2.0.1
Install-Package Microsoft.Owin.Cors -Version 2.1.0
Install-Package EntityFramework -Version 6.0.0
Step 5:在项目根目录下添加Owin“Startup”类
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(WebApi.Startup))]
namespace WebApi
{
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,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(),
Provider = new SimpleAuthorizationServerProvider()
};
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
}
}
Step 6:删除Global.asax
我们已经设置了Setup类,就不需要Global了,删掉干净;
Step 7:在项目根目录下添加验证类 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 WebApi
{
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); }
}
}
Step 7:让CORS起作用
在ASP.NET Web API中启用OAuth的Access Token验证非常简单,只需在相应的Controller或Action加上[Authorize]标记
修改ProductsController类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web.Http; using WebApi.Models; namespace WebApi.Controllers
{ public class ProductsController : ApiController
{
Product[] products = new Product[]
{
new Product { Id = , Name = "Tomato Soup", Category = "Groceries", Price = },
new Product { Id = , Name = "Yo-yo", Category = "Toys", Price = 3.75M },
new Product { Id = , Name = "Hammer", Category = "Hardware", Price = 16.99M }
}; [Authorize]
[Route("")]
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]
public IEnumerable<Product> GetProductsByCategory(string category)
{
return products.Where(p => string.Equals(p.Category, category,
StringComparison.OrdinalIgnoreCase));
}
}
}
现在我们再次直接GET http://localhost:23477/api/products/ 会返回401错误,请求被拒绝
获取token, POST http://localhost:23477/token
参数BODY x-www-form-urlencoded 格式:
grant_type=password
username=admin
password=123456
返回200状态,内容为:
{
"access_token": "eLjAu3Alm2YWjJKXmX_fLY07P6vbIzxasFECkDap3KIE0Ydp7IGhTgrzWLtPdgrK46rfAB-OmJSG5C8Bh-PkfG3XrGS0uDea2KBXyoWSR11evTGJiVIyXny3Ih2DkH04qH2T_Ar4kIjcAngPtUnsEVex26tV4QHIrjCq5SlkOdfdAa9Pnl98QVwYH47yO-zlc55bwMgpR2J4fQLyNzWVHNZpH3DbOcHQ3Yenemr6XhM",
"token_type": "bearer",
"expires_in":
}
只要在http请求头中加上Authorization:bearer Token就可以成功访问API就成功了:
GET http://localhost:23477/api/products/
Authorization : bearer eLjAu3Alm2YWjJKXmX_fLY07P6vbIzxasFECkDap3KIE0Ydp7IGhTgrzWLtPdgrK46rfAB-OmJSG5C8Bh-PkfG3XrGS0uDea2KBXyoWSR11evTGJiVIyXny3Ih2DkH04qH2T_Ar4kIjcAngPtUnsEVex26tV4QHIrjCq5SlkOdfdAa9Pnl98QVwYH47yO-zlc55bwMgpR2J4fQLyNzWVHNZpH3DbOcHQ3Yenemr6XhM
这样我们就完成了简单的WEB API的token验证~
不过这个程序有个问题,如果GetProductById也加上验证那么根据ID获取product的接口 http://localhost:23477/api/products/1 会报错
需要修改成 http://localhost:23477/api/products?id=1
不知道是哪里出的问题
本文代码: http://pan.baidu.com/s/1jGxZVKU
PostMan工具请移步这里看介绍 http://www.cnblogs.com/wade-xu/p/4228954.html
ASP.NET Web API 2基于令牌的身份验证的更多相关文章
- ASP.NET Web Api构建基于REST风格的服务实战系列教程
使用ASP.NET Web Api构建基于REST风格的服务实战系列教程[十]——使用CacheCow和ETag缓存资源 系列导航地址http://www.cnblogs.com/fzrain/p/3 ...
- ASP.NET WEB API构建基于REST风格
使用ASP.NET WEB API构建基于REST风格的服务实战系列教程[开篇] 最近发现web api很火,园内也有各种大神已经在研究,本人在asp.net官网上看到一个系列教程,原文地址:http ...
- [转]ASP.NET Web API(三):安全验证之使用摘要认证(digest authentication)
本文转自:http://www.cnblogs.com/parry/p/ASPNET_MVC_Web_API_digest_authentication.html 在前一篇文章中,主要讨论了使用HTT ...
- ASP.NET Web API(三):安全验证之使用摘要认证(digest authentication)
在前一篇文章中,主要讨论了使用HTTP基本认证的方法,因为HTTP基本认证的方式决定了它在安全性方面存在很大的问题,所以接下来看看另一种验证的方式:digest authentication,即摘要认 ...
- 购物车Demo,前端使用AngularJS,后端使用ASP.NET Web API(3)--Idetity,OWIN前后端验证
原文:购物车Demo,前端使用AngularJS,后端使用ASP.NET Web API(3)--Idetity,OWIN前后端验证 chsakell分享了前端使用AngularJS,后端使用ASP. ...
- 使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【开篇】【持续更新中。。。】
最近发现web api很火,园内也有各种大神已经在研究,本人在asp.net官网上看到一个系列教程,原文地址:http://bitoftech.net/2013/11/25/detailed-tuto ...
- 使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【九】——API变了,客户端怎么办?
系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 一旦我们将API发布之后,消费者就会开始使用并和其他的一些数据混在一起.然而,当新的需求出现 ...
- ASP.NET Web API(二):安全验证之使用HTTP基本认证
在前一篇文章ASP.NET Web API(一):使用初探,GET和POST数据中,我们初步接触了微软的REST API: Web API. 我们在接触了Web API的后就立马发现了有安全验证的需求 ...
- 【ASP.NET Web API教程】6.4 模型验证
本文是Web API系列教程的第6.4小节 6.4 Model Validation 6.4 模型验证 摘自:http://www.asp.net/web-api/overview/formats-a ...
随机推荐
- PHP程序员进阶学习书籍参考指南
PHP程序员进阶学习书籍参考指南 @heiyeluren lastmodify: 2016/2/18 [初阶](基础知识及入门) 01. <PHP与MySQL程序设计(第4版)> ...
- OOCSS的概念和思路
<概念> <思路> 面向对象的CSS有两个原则: 独立的结构和样式 独立的容器和内容 以下几点是创建OOCSS的关键部分: 创建一个组件库 独立的容器和内容,并且避免样式来依赖 ...
- 08.03 js _oop
js 分6个基本类型: string boolean number undefind null 自定义对象 对象的种类: js内置的 ( 比如 string number ) 宿主对象 (比如 ...
- day3
程序1: 实现简单的shell sed替换功能 ]new = sys.argv[]file_name = sys.argv[]tmp_file ="tmpfile"open(tmp ...
- c/c++ printf
%d int %s string %p point值 %c char %lu long unsigned int
- [jquery]添加行内容后根据下拉菜单选择内容对比之前已有选项,若有重置再提示
今天页面上一个添加列内容时,要对选择内容与之前已有选项内容作对比,防止用户重复选择内容 页面HTML代码 <ul class="list-group xj-list-NObor xj- ...
- 取两个DataTable的交集,删除重复数据
/// <summary> /// 取两个DataTable的交集,删除重复数据 /// </summary> /// <param name="sourceD ...
- IT干货
最近翻看Redis相关的中文书籍时,发现了很多错误,包括翻译错误及理论错误,因此想搜集一些相关的外文书籍看看.以下几个链接,内容大同小异,均可免费下载相关的英文书籍PDF版,内容涵盖了IT的方方面面. ...
- 【maven】maven创建web项目-pom文件提示web.xml is missing and <failOnMissingWebXml> is set to true
使用maven创建web项目,选择war类型后,pom文件红叉 提示web.xml is missing and <failOnMissingWebXml> is set to true ...
- android--gradle编译龟速?offline!