使用OAuth、Identity创建WebApi认证接口供客户端调用
前言
现在的web app基本上都是前后端分离,之前接触的大部分应用场景最终产品都是部署在同一个站点下,那么随着WebApi(Restful api)的发展前后端实现的完全分离,前端不在后端框架的页面基础上开发,也就告别传统上的Session判断客户端登陆用户的情况。OAuth已发布很久,Asp.Net Identity也发布很久。看了几篇朋友写的博客才把这几个sample写完,也解决了之前我对前后端完全分离产生的一些疑惑。
OAuth2.0的4种角色
- resource owner资源所有者:比如twitter用户,他在twitter的数据就是资源,他自己就是这些资源的所有者
- resource server资源服务器:保存资源的服务器,别人要访问受限制的资源就要出示 Access Token(访问另牌)
- client客户端:一个经过授权后,可以代表资源所有者访问资源服务器上受限制资源的一方。比如 开发者开发的应用
- authorization server授权服务器:对 资源所有者进行认证,认证通过后,向 客户端发放 Access Token(访问另牌
OAuth2.0取得Access Token的4种方式
- 授权码模式(authorization code)
- 简化模式(implicit)
- 密码模式(resource owner password credentials)
- 客户端模式(client credentials)
使用Owin实现密码模式(OAuth2.0密码模式)
1、使用VS2015创建一个Empty WebApi项目。
2、使用Nuget导入核心命名空间。
Install-Package Microsoft.AspNet.WebApi.Owin
[assembly:OwinStartup(typeof(AspNet_Identity_Demo.Startup))]
namespace AspNet_Identity_Demo
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
WebApiConfig.Register(config);
app.UseWebApi(config);
}
}
}
4、修改WebApiConfig。修改最后两句代码,主要以CamelCase命名法序列化webApi的返回结果。
namespace AspNet_Identity_Demo
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API 配置和服务 // Web API 路由
config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
); //用json的方式返回webapi接口返回值
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
}
}
}
5、删除Global.asax。添加Startup类后暂时用不到这个类。
6、添加Asp.Net Identity。先添加Identity类库。
Install-Package Microsoft.AspNet.Identity.Owin
namespace AspNet_Identity_Demo.Models
{
public class AuthContext:IdentityDbContext<IdentityUser>
{
public AuthContext() : base("AuthContext")
{ }
}
}
Web.config中增加connectionString
<add name="AuthContext" connectionString="Data Source=.;User Id=sa;password=111111;Initial Catalog=AspNet_Identity;Integrated Security=SSPI;" providerName="System.Data.SqlClient" />
8、在Models文件夹中创建UserModel.cs
public class UserModel
{
[Required]
[Display(Name ="User Name")]
public string UserName { get; set; }
[Required]
[DataType(DataType.Password)]
[StringLength(100,ErrorMessage ="The {0} must be at least {2} characters long",MinimumLength =6)]
public string Password { get; set; } [Required]
[DataType(DataType.Password)]
[Compare("Password",ErrorMessage ="The password and confirmpassword are not matched...")]
public string ConfirmPassword { get; set; }
}
9、添加Asp.Net Identity 仓储支持类。
这里用到了策略模式,把你实现的UserStore.cs作为参数传进UserManager构造函数中。
namespace AspNet_Identity_Demo.Models
{
public class AuthRepository : IDisposable
{
private AuthContext _ctx;
private UserManager<IdentityUser> _userManager;
public AuthRepository()
{
_ctx = new AuthContext();
_userManager = new UserManager<IdentityUser>(new UserStore<IdentityUser>(_ctx));
} public async Task<IdentityResult> Register(UserModel model)
{
IdentityUser user = new IdentityUser()
{
UserName = model.UserName
}; IdentityResult result = await _userManager.CreateAsync(user,model.Password); return result;
} public async Task<IdentityUser> FindUser(UserModel model)
{
IdentityUser user = await _userManager.FindAsync(model.UserName, model.Password); return user;
} public async Task<IdentityUser> FindUserByName(string username)
{
IdentityUser user = await _userManager.FindByNameAsync(username);
return user;
} public void Dispose()
{
_ctx.Dispose();
_userManager.Dispose();
}
}
}
10、添加AccountController.cs
给Controller添加webapi访问前缀,我的是apix,访问时也就是http://localhost:8083/apix/account/register。
namespace AspNet_Identity_Demo.Controllers
{
[RoutePrefix("apix/Account")]
public class AccountController : ApiController
{
private AuthRepository _authRepo;
public AccountController()
{
_authRepo = new AuthRepository();
} [AllowAnonymous]
[Route("Register")]
public async Task<IHttpActionResult> Register(UserModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
} IdentityResult result = await _authRepo.Register(model);
IHttpActionResult errorResult = GetError(result);
if (errorResult != null)
{
return errorResult;
}
return Ok();
} private IHttpActionResult GetError(IdentityResult result)
{
if (result == null)
{
return InternalServerError();
} if (!result.Succeeded)
{
foreach (string err in result.Errors)
{
ModelState.AddModelError("", err);
} if (ModelState.IsValid)
{
return BadRequest();
} return BadRequest(ModelState);
} return null;
}
}
}
OK,到了这一步就可以在你的视线之上注册用户了,使用Postman调用接口并调用接口http://localhost:8080/apix/account/register。post方式调用。参数传UserName、Password。 调用成功返回接口返回200.打开你的SQL Server。调用成功的话数据库用到的几张表都会生成。用户表是dbo.AspNetUsers.

11、添加一个数据访问controller,OrdersController。
namespace AspNet_Identity_Demo.Controllers
{
[Authorize]
[RoutePrefix("apix/orders")]
public class OrdersController : ApiController
{
[Route]
public IHttpActionResult Get()
{
return Ok(Order.CreateOrders());
}
} public class Order
{
public int OrderID { get; set; }
public string CustomerName { get; set; }
public string ShipperCity { get; set; }
public Boolean IsShipped { get; set; } public static List<Order> CreateOrders()
{
List<Order> OrderList = new List<Order>
{
new Order {OrderID = 10248, CustomerName = "Taiseer Joudeh", ShipperCity = "Amman", IsShipped = true },
new Order {OrderID = 10249, CustomerName = "Ahmad Hasan", ShipperCity = "Dubai", IsShipped = false},
new Order {OrderID = 10250,CustomerName = "Tamer Yaser", ShipperCity = "Jeddah", IsShipped = false },
new Order {OrderID = 10251,CustomerName = "Lina Majed", ShipperCity = "Abu Dhabi", IsShipped = false},
new Order {OrderID = 10252,CustomerName = "Yasmeen Rami", ShipperCity = "Kuwait", IsShipped = true}
}; return OrderList;
}
}
}
12、添加OAuth Bearer Token支持类库 Install-Package Microsoft.Owin.Security.OAuth
13、回到Startup。添加创建token方法,主要涉及到了两个类SimpleAuthorizationServerProvider、OAuthAuthorizationServerOptions。
[assembly:OwinStartup(typeof(AspNet_Identity_Demo.Startup))]
namespace AspNet_Identity_Demo
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
ConfigAuth(app);
WebApiConfig.Register(config);
app.UseCors(CorsOptions.AllowAll);
app.UseWebApi(config);
} public void ConfigAuth(IAppBuilder app)
{
OAuthAuthorizationServerOptions option = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp=true,
TokenEndpointPath=new PathString("/token"),
AccessTokenExpireTimeSpan=TimeSpan.FromDays(1),
Provider=new SimpleAuthorizationServerProvider()
}; app.UseOAuthAuthorizationServer(option);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
} 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(
new UserModel() { UserName=context.UserName,Password=context.Password});
if (user == null)
{
context.SetError("invalid_grant", "The username 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);
}
}
}
访问http://localhost:8083/token http接口生成token。过期时间24小时。SimpleAuthorizationServerProvider 在该类中实现用户验证和口令生成。 注意这里的ClamisIdentity。该类在命名空间:System.Security.Claims。 生成token主要是context.Validated(identity);这句代码。
OK,现在可以注册用户,也可以生成token了。那么现在有个问题来了,前后端完全分离后,那么肯定要实现跨域访问(CORS)。所以你看到重写GrantResourceOwnerCredentials第一句就是添加Access-Control-Allow-Origin支持。
13、添加Asp.Net WebApi Install-Package Microsoft.Owin.Cors。在Startup.cs Configuration方法中添加app.UseCors(CorsOptions.AllowAll);
14、生成客户端token。

15、拿到token后,访问数据接口。注意参数Authorization值有前缀Bearer。

总结
总的来说Owin和Identity的设计还是有点复杂的,约定的东西多一些。相比微软早起的Membership则要优雅很多,原理和实现背后的细节还要多多挖掘,才能体会到其中的魅力。比如ClamisIdentity、 UserManager、UserStore。
Demo下载地址:https://yunpan.cn/c6yNPKhzpQgmx (提取码:0575)
参考资料
http://www.cnblogs.com/richieyang/p/4918819.html
http://bitoftech.net/2014/06/01/token-based-authentication-asp-net-web-api-2-owin-asp-net-identity/
http://www.cnblogs.com/pengyingh/articles/2377968.html
http://www.cnblogs.com/keepfool/p/5665953.html
使用OAuth、Identity创建WebApi认证接口供客户端调用的更多相关文章
- SpringCloud系列二:Restful 基础架构(搭建项目环境、创建 Dept 微服务、客户端调用微服务)
1.概念:Restful 基础架构 2.具体内容 对于 Rest 基础架构实现处理是 SpringCloud 核心所在,其基本操作形式在 SpringBoot 之中已经有了明确的讲解,那么本次为 了清 ...
- Tomcat下HTTPS双向认证配置以及客户端调用案例
1:生成服务器端的keystore和truststore文件 (1)以jks格式生成服务器端包含Public key和Private Key的keystore文件 keytool -genkey -a ...
- 使用ASP.NET Identity 实现WebAPI接口的Oauth身份验证
使用ASP.NET Identity 实现WebAPI接口的Oauth身份验证 目前WEB 前后端分离的开发模式比较流行,之前做过的几个小项目也都是前后分离的模式,后端使用asp.net weba ...
- OAuth做webapi认证
OAuth做webapi认证 看到园子里面有人写的OAuth,就想把自己实现的OAuth也分享一下,关于OAuth协议这里就不再赘述. 一.作为认证服务器,首先需要提供一个可以通过appid/apps ...
- Swagger与OAuth 手动搭建WebApi 操作笔记
1.创建一个空的Web应用程序 2.通过nuget 安装以下插件清单,有部分会在安装其他插件时候自动安装: 3.安装完Swagger 会生成一个目录App_Start,在这个目录中增加文件ApiCon ...
- React + Node 单页应用「二」OAuth 2.0 授权认证 & GitHub 授权实践
关于项目 项目地址 预览地址 记录最近做的一个 demo,前端使用 React,用 React Router 实现前端路由,Koa 2 搭建 API Server, 最后通过 Nginx 做请求转发. ...
- IdentityServer4结合AspNetCore.Identity实现登录认证踩坑填坑记录
也可以自定义实现,不使用IdentityServer4.AspNetIdentity这个包,当然还要实现其他接口IResourceOwnerPasswordValidator. IProfileSer ...
- Asp.Net Identity 2.0 认证
转Asp.Net Identity 2.0 认证 一个星期前,也就是3月20日,微软发布了Asp.Net Identity 2.0 RTM.功能更加强大,也更加稳定.Identity这个东西现在版本还 ...
- Yii2 restful api创建,认证授权以及速率控制
Yii2 restful api创建,认证授权以及速率控制 下面是对restful从创建到速率控制的一个详细流程介绍,里面的步骤以及截图尽可能详细,熟悉restful的盆友可能觉得过于繁琐,新手不妨耐 ...
随机推荐
- NodeJs在Linux下使用的各种问题
环境:ubuntu16.04 ubuntu中安装NodeJs 通过apt-get命令安装后发现只能使用nodejs,而没有node命令 如果想避免这种情况请看下面连接的这种安装方式: 拓展见:Linu ...
- .NET Core系列 : 1、.NET Core 环境搭建和命令行CLI入门
2016年6月27日.NET Core & ASP.NET Core 1.0在Redhat峰会上正式发布,社区里涌现了很多文章,我也计划写个系列文章,原因是.NET Core的入门门槛相当高, ...
- javascript表单的Ajax 提交插件的使用
Ajax 提交插件 form.js 表单的下载地址:官方网站:http://malsup.com/jquery/form/ form.js 插件有两个核心方法:ajaxForm()和ajaxSubmi ...
- MAC Osx PHP安装指导
php.ini的位置 Mac OS X中没有默认的php.ini文件,但是有对应的模版文件php.ini.default,位于/private/etc/php.ini.default 或者说 /etc ...
- 小兔JS教程(三)-- 彻底攻略JS回调函数
这一讲来谈谈回调函数. 其实一句话就能概括这个东西: 回调函数就是把一个函数当做参数,传入另一个函数中.传进去的目的仅仅是为了在某个时刻去执行它. 如果不执行,那么你传一个函数进去干嘛呢? 就比如说对 ...
- html中table边框属性
1.向右(横向)合并: <td colspan="5"><span>后台管理系统</span></td> 2.向下(纵向)合并: & ...
- 我的屌丝giser成长记-工作篇之B公司
从A公司跳槽到B公司,岗位还是webgis开发方向,但是具体实现的技术完全变了,从flex转换js,这也是我要离开A公司的最重要的原意之一:A公司的arcgis for flex框架采用了flexvi ...
- [Hadoop in Action] 第6章 编程实践
Hadoop程序开发的独门绝技 在本地,伪分布和全分布模式下调试程序 程序输出的完整性检查和回归测试 日志和监控 性能调优 1.开发MapReduce程序 [本地模式] 本地模式 ...
- Python学习基础
1.使用范围: 大数据 .图像处理.web .运维.爬虫.自动化.科学计算 2.准备环境: linux/mac python 3.5.2 ipython vim/sublime/atom 3.列表 3 ...
- 希尔排序(java)
时间复杂度为O( n^(3/2) )不是一个稳定的排序算法 如何看一个算法是否稳定:{("scala",12),("python",34),("c++ ...