标题叙述:

概述

概述

上一篇大家介绍了什么利用vue resource管理HTTP诉求,结合服务端的REST
API,就可见很轻易地营造三个增加和删除查改应用。
以此应用始终遗留了贰个标题,Web App在拜谒REST
API时,未有通过其余表达,那使得服务端的REST
API是不安全的,只要有人知道api地址,就足以调用API对服务端的能源进行修改和删除。
前几天大家就来研商一下怎么样整合Web API来限制能源的拜访。

正文的要紧内容如下:

  • 介绍古板的Web应用和根据REST服务的Web应用
  • 介绍OAuth认证流程和密码情势
  • 创办四个依照ASP.NET Identity的Web API应用程序
  • 基于$.ajax实现OAuth的注册、登录、注销和API调用
  • 基于vue-resource实现OAuth的注册、登录、注销和API调用

正文的尾声示例是整合上一篇的CUHighlanderD,本文的报到、注册、注销和API调用功效实现的。

亚洲城ca88 1

正文9个示范的源码已停放GitHub,假诺您认为本篇内容科学,请点个赞,或在GitHub上加个少于!

Page
Demo
GitHub
Source

听别人讲$.ajax的演示如下:

挂号示例
报到和撤消示例
报到获取token并调用API示例
挂号、登陆、注销、调用API综合示范

传说vue-resource的演示如下:

登记示例
签到和注销示例
签到获取token并调用API示例
登记、登入、注销、调用API综合示范

当大家用swagger UI对Web API 进行测量试验时报401谬误

上一篇大家介绍了何等使用vue resource管理HTTP诉求,结合服务端的REST
API,就可见很轻便地创设二个增加和删除查改应用。
其一利用始终遗留了三个难点,Web App在拜候REST
API时,没有经过其余注脚,那使得服务端的REST
API是不安全的,只要有人明白api地址,就可以调用API对服务端的财富开展修改和删除。
前些天大家就来探究一下哪些结合Web API来界定财富的访谈。

OAuth介绍

我们点开GET /api/services/app/Role/GetAll,输入参数

本文的要害内容如下:

传统的Web应用

在守旧的Web应用程序中,前后端是身处一个站点下的,大家得以因此对话(Session)来保存客商的新闻。
比如:二个简短的ASP.NET
MVC应用程序,客商登陆成功后,大家将顾客的ID记录在Session中,假诺为Session[“UserID”]。
前面三个发送ajax需要时,假诺这么些必要需求已报到的客商能力访问,大家只需在后台Controller中验证Session[“UserID”]是还是不是为空,就足以看清客户是还是不是已经报到了。
那也是观念的Web应用可以避开HTTP面向无连接的方法。

 亚洲城ca88 2

  1. 介绍古板的Web应用和依靠REST服务的Web应用
  2. 介绍OAuth认证流程和密码方式
  3. 开创四个根据ASP.NET Identity的Web API应用程序
  4. 基于$.ajax实现OAuth的注册、登录、注销和API调用
  5. 基于vue-resource实现OAuth的注册、登录、注销和API调用

基于REST服务的Web应用

前几日广大行使,客商端和服务端是分开的,服务端是依附REST风格创设的一套Service,客商端是第三方的Web应用,顾客端通过跨域的ajax诉求获取REST服务的能源。
不过REST
瑟维Stone常是被规划为无状态的(Stateless),那代表大家无法借助于Session来保存顾客新闻,也不可能利用Session[“UserID”]这种情势明确客商身份。

焚林而猎这些主题材料的情势是何许吧?常规的法子是选用OAuth 2.0。
对于顾客相关的OpenAPI,为了掩护客商数量的安全和隐衷,第三方Web应用访谈顾客数量前都供给显式的向顾客征求授权。
对照于OAuth 1.0,OAuth 2.0的求证流程进一步简便易行。

点击Try it out!按钮,报401错误

正文的尾声示例是结合上一篇的CUTucsonD,本文的报到、注册、注销和API调用成效完毕的。

专项使用名词介绍

在精晓OAuth 2.0事先,大家先通晓几个名词:

  1. Resource:能源,和REST中的能源概念一样,某个财富是拜谒受保障的
  2. Resource Server:寄存财富的服务器
  3. Resource Owner:财富全部者,本文中又叫做客户(user)
  4. User Agent:顾客代理,即浏览器
  5. Client: 访谈财富的顾客端,也便是应用程序
  6. Authorization
    Server
    :认证服务器,用于给Client提供访谈令牌的服务器
  7. Access Token:访问能源的令牌,由Authorization
    Server器授予,Client访谈Resource时,需提供Access Token
  8. Bearer Token:Bearer Token是Access Token的一种,另一种是Mac
    Token。
    Bearer Token的行使格式为:Bearer XXXXXXXX

Token的等级次序请参见:

不时认证服务器和财富服务器能够是一台服务器,本文中的Web
API示例就是这种使用处境。

 亚洲城ca88 3

亚洲城ca88 4

OAuth认证流程

在驾驭那多少个词今后,我们用这多少个名词来编个旧事。

 

正文9个示范的源码已停放GitHub:

简化版本

其一典故的简化版本是:顾客(Resource Owner)访谈能源(Resource)。

亚洲城ca88 5

由来和消除方案

OAuth介绍

现实版本

简化版的旧事唯有三个结出,下边是以此典故的求实版本:

  1. 客户通过浏览器张开顾客端后,顾客端需要顾客给予授权。
    客商端能够平素将授权央求发给客户(如图所示),大概发送给贰当中档媒介,举例认证服务器。
  2. 顾客同意授予顾客端授权,顾客端收到客户的授权。
    授权格局(GrantType)决意于客户端应用的形式,以及表明服务器所辅助的方式。
  3. 客商端提供身份音讯,然后向认证服务器发送需要,申请访问令牌
  4. 注明服务器验证顾客端提供的身份音信,假若表明通过,则向客商端发放令牌
  5. 客商端采取访谈令牌,向资源服务器哀告受保证的财富
  6. 财富服务器验证访谈令牌,借使可行,则向客商端开放财富

亚洲城ca88 6

上述多少个步骤,(B)是较为主要的贰个,即顾客怎么着本事给顾客端授权。有了那几个授权未来,顾客端就足以拿走令牌,进而通过临牌获取财富。那也是OAuth
2.0的运维流程,详细的情况请参谋:

翻开右上角有个葱绿惊讶号的Logo

传统的Web应用

顾客端的授权格局

客户端必需获得顾客的授权(authorization grant),本领猎取令牌(access
token)。

OAuth 2.0定义了三种授权格局:

  • 授权码形式(authorization code)
  • 简化格局(implicit)
  • 密码形式(resource owner password credentials)
  • 客商端模式(client credentials)

正文的演示是根据密码格局的,笔者就只简轻便单介绍这种情势,别的3自家就不介绍了,大家风乐趣能够看阮大的篇章:

 亚洲城ca88 7

在观念的Web应用程序中,前后端是放在几个站点下的,我们得以因此对话(Session)来保存用户的新闻。

密码情势

密码形式(Resource Owner Password Credentials
Grant)中,客商向顾客端提供温馨的客户名和密码。客户端应用那一个新闻,向服务端申请授权。

在这种形式中,客户必得把团结的密码给顾客端,可是客商端不可存款和储蓄密码。那平时用在客户对顾客端高度信赖的情况下,譬喻客商端是操作系统的一有个别,大概由四个出名集团出品。

亚洲城ca88 8

密码嘛事的试行步骤如下:

(A)客户向顾客端提供客商名和密码。

(B)客商端将顾客名和密码发给认证服务器,向后面一个央求令牌。

(C)认证服务器确认准确后,向客户端提供访谈令牌。

(B)步骤中,顾客端发出的HTTP央求,包罗以下参数:

  • grant_type:表示授权类型,此处的值固定为”password”,必选项。
  • username:表示客商名,必选项。
  • password:表示客商的密码,必选项。
  • scope:表示权限限制,可选项。

小心:在背后的顾客端示例中,除了提供username和password,grant_type也是必须钦定为”password”,不然不或许获得服务端的授权。

点击查阅原因是造访API须求输入授权token值举行求证,token值是后台根据登陆顾客动态变化的,怎么着获得呢?

例如:三个简约的ASP.NET
MVC应用程序,客商登陆成功后,我们将客户的ID记录在Session中,若是为Session[“UserID”]。
前面三个发送ajax诉求时,若是这一个央求须求已登陆的客户才具访谈,咱们只需在后台Controller中验证Session[“UserID”]是否为空,就足以肯定客户是不是业已报到了。

服务端碰到筹算

若果你是前端开拓职员,而且未触及过ASP.NET Web API,能够跳过此段子。

亚洲城ca88 9

Authentication选择Individual User Accounts

亚洲城ca88 10

成立那一个Web API工程时,VS会自行引进Owin和AspNet.Identity相关的库。

亚洲城ca88 11

修改ValuesController,除了IEnumerable<string> Get()操作外,其余操作都剔除,并为该操作使用[Authorize]天性,那表示客商端必需通过身份验证后才具调用该操作。

public class ValuesController : ApiController
{
    // GET: api/Values
    [Authorize]
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }
}

 亚洲城ca88 12

那也是守旧的Web应用能够避开HTTP面向无连接的主意。

添加Model, Controller

亚洲城ca88 13

亚洲城ca88 14

亚洲城ca88 15

不留余地方案一:

基于REST服务的Web应用

起始化数据库

亚洲城ca88 16

推行以下3个指令

亚洲城ca88 17

亚洲城ca88 18

施行以下SQL语句:

亚洲城ca88 19 展现代码

SET IDENTITY_INSERT [dbo].[Customers] ON 

INSERT [dbo].[Customers] ([CustomerId], [CustomerCode], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax], [CustomerType]) VALUES (1, N'ALFKI', N'Alfreds Futterkiste', N'Maria Anders', N'Sales Representative', N'Obere Str. 57', N'Berlin', NULL, N'12209', N'Germany', N'030-0074321', N'030-0076545', 1)
INSERT [dbo].[Customers] ([CustomerId], [CustomerCode], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax], [CustomerType]) VALUES (2, N'ANATR', N'Ana Trujillo Emparedados y helados', N'Ana Trujillo', N'Owner', N'Avda. de la Constitución 2222', N'México D.F.', NULL, N'05021', N'Mexico', N'(5) 555-4729', N'(5) 555-3745', 1)
INSERT [dbo].[Customers] ([CustomerId], [CustomerCode], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax], [CustomerType]) VALUES (3, N'ANTON', N'Antonio Moreno Taquería', N'Antonio Moreno', N'Owner', N'Mataderos  2312', N'México D.F.', NULL, N'05023', N'Mexico', N'(5) 555-3932', NULL, 1)
INSERT [dbo].[Customers] ([CustomerId], [CustomerCode], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax], [CustomerType]) VALUES (4, N'AROUT', N'Around the Horn', N'Thomas Hardy', N'Sales Representative', N'120 Hanover Sq.', N'London', NULL, N'WA1 1DP', N'UK', N'(171) 555-7788', N'(171) 555-6750', 1)
INSERT [dbo].[Customers] ([CustomerId], [CustomerCode], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax], [CustomerType]) VALUES (5, N'BERGS', N'Berglunds snabbköp', N'Christina Berglund', N'Order Administrator', N'Berguvsvägen  8', N'Luleå', NULL, N'S-958 22', N'Sweden', N'0921-12 34 65', N'0921-12 34 67', 1)
INSERT [dbo].[Customers] ([CustomerId], [CustomerCode], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax], [CustomerType]) VALUES (6, N'BLAUS', N'Blauer See Delikatessen', N'Hanna Moos', N'Sales Representative', N'Forsterstr. 57', N'Mannheim', NULL, N'68306', N'Germany', N'0621-08460', N'0621-08924', 1)
INSERT [dbo].[Customers] ([CustomerId], [CustomerCode], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax], [CustomerType]) VALUES (7, N'BLONP', N'Blondesddsl père et fils', N'Frédérique Citeaux', N'Marketing Manager', N'24, place Kléber', N'Strasbourg', NULL, N'67000', N'France', N'88.60.15.31', N'88.60.15.32', 1)
INSERT [dbo].[Customers] ([CustomerId], [CustomerCode], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax], [CustomerType]) VALUES (8, N'BOLID', N'Bólido Comidas preparadas', N'Martín Sommer', N'Owner', N'C/ Araquil, 67', N'Madrid', NULL, N'28023', N'Spain', N'(91) 555 22 82', N'(91) 555 91 99', 1)
INSERT [dbo].[Customers] ([CustomerId], [CustomerCode], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax], [CustomerType]) VALUES (9, N'BONAP', N'Bon app''', N'Laurence Lebihan', N'Owner', N'12, rue des Bouchers', N'Marseille', NULL, N'13008', N'France', N'91.24.45.40', N'91.24.45.41', 1)
INSERT [dbo].[Customers] ([CustomerId], [CustomerCode], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax], [CustomerType]) VALUES (10, N'BOTTM', N'Bottom-Dollar Markets', N'Elizabeth Lincoln', N'Accounting Manager', N'23 Tsawassen Blvd.', N'Tsawassen', N'BC', N'T2F 8M4', N'Canada', N'(604) 555-4729', N'(604) 555-3745', 1)
INSERT [dbo].[Customers] ([CustomerId], [CustomerCode], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax], [CustomerType]) VALUES (11, N'BSBEV', N'B''s Beverages', N'Victoria Ashworth', N'Sales Representative', N'Fauntleroy Circus', N'London', NULL, N'EC2 5NT', N'UK', N'(171) 555-1212', NULL, 1)
INSERT [dbo].[Customers] ([CustomerId], [CustomerCode], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax], [CustomerType]) VALUES (12, N'CACTU', N'Cactus Comidas para llevar', N'Patricio Simpson', N'Sales Agent', N'Cerrito 333', N'Buenos Aires', NULL, N'1010', N'Argentina', N'(1) 135-5555', N'(1) 135-4892', 1)
INSERT [dbo].[Customers] ([CustomerId], [CustomerCode], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax], [CustomerType]) VALUES (13, N'CENTC', N'Centro comercial Moctezuma', N'Francisco Chang', N'Marketing Manager', N'Sierras de Granada 9993', N'México D.F.', NULL, N'05022', N'Mexico', N'(5) 555-3392', N'(5) 555-7293', 1)
INSERT [dbo].[Customers] ([CustomerId], [CustomerCode], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax], [CustomerType]) VALUES (14, N'CHOPS', N'Chop-suey Chinese', N'Yang Wang', N'Owner', N'Hauptstr. 29', N'Bern', NULL, N'3012', N'Switzerland', N'0452-076545', NULL, 1)
INSERT [dbo].[Customers] ([CustomerId], [CustomerCode], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax], [CustomerType]) VALUES (15, N'COMMI', N'Comércio Mineiro', N'Pedro Afonso', N'Sales Associate', N'Av. dos Lusíadas, 23', N'Sao Paulo', N'SP', N'05432-043', N'Brazil', N'(11) 555-7647', NULL, 1)
INSERT [dbo].[Customers] ([CustomerId], [CustomerCode], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax], [CustomerType]) VALUES (16, N'CONSH', N'Consolidated Holdings', N'Elizabeth Brown', N'Sales Representative', N'Berkeley Gardens 12  Brewery', N'London', NULL, N'WX1 6LT', N'UK', N'(171) 555-2282', N'(171) 555-9199', 1)
INSERT [dbo].[Customers] ([CustomerId], [CustomerCode], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax], [CustomerType]) VALUES (17, N'DRACD', N'Drachenblut Delikatessen', N'Sven Ottlieb', N'Order Administrator', N'Walserweg 21', N'Aachen', NULL, N'52066', N'Germany', N'0241-039123', N'0241-059428', 1)
INSERT [dbo].[Customers] ([CustomerId], [CustomerCode], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax], [CustomerType]) VALUES (18, N'DUMON', N'Du monde entier', N'Janine Labrune', N'Owner', N'67, rue des Cinquante Otages', N'Nantes', NULL, N'44000', N'France', N'40.67.88.88', N'40.67.89.89', 1)
INSERT [dbo].[Customers] ([CustomerId], [CustomerCode], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax], [CustomerType]) VALUES (19, N'EASTC', N'Eastern Connection', N'Ann Devon', N'Sales Agent', N'35 King George', N'London', NULL, N'WX3 6FW', N'UK', N'(171) 555-0297', N'(171) 555-3373', 1)
INSERT [dbo].[Customers] ([CustomerId], [CustomerCode], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax], [CustomerType]) VALUES (20, N'ERNSH', N'Ernst Handel', N'Roland Mendel', N'Sales Manager', N'Kirchgasse 6', N'Graz', NULL, N'8010', N'Austria', N'7675-3425', N'7675-3426', 1)

SET IDENTITY_INSERT [dbo].[Customers] OFF

CustomersController类有5个Action,除了2个GET央浼外,别的3个须要分别是POST,
PUT和DELETE。
为那3个央浼加多[Authorize]特色,那3个恳求必得经过身份验证技艺访谈。

亚洲城ca88 20 掩盖代码

public class CustomersController : ApiController
{
    private ApplicationDbContext db = new ApplicationDbContext();

    // GET: api/Customers
    public IQueryable<Customer> GetCustomers()
    {
        return db.Customers;
    }

    // GET: api/Customers/5
    [ResponseType(typeof(Customer))]
    public async Task<IHttpActionResult> GetCustomer(int id)
    {
        Customer customer = await db.Customers.FindAsync(id);
        if (customer == null)
        {
            return NotFound();
        }

        return Ok(customer);
    }

    // PUT: api/Customers/5
    [Authorize]
    [ResponseType(typeof(void))]
    public async Task<IHttpActionResult> PutCustomer(int id, Customer customer)
    {
      // ...
    }

    // POST: api/Customers
    [Authorize]
    [ResponseType(typeof(Customer))]
    public async Task<IHttpActionResult> PostCustomer(Customer customer)
    {
        // ...
    }

    // DELETE: api/Customers/5
    [ResponseType(typeof(Customer))]
    [Authorize]
    public async Task<IHttpActionResult> DeleteCustomer(int id)
    {
        // ...
    }
}

有个一向拿走授权token的API:/api/TokenAuth/Authenticate

今日众多运用,顾客端和服务端是分开的,服务端是依照REST风格创设的一套Service,顾客端是第三方的Web应用,顾客端通过跨域的ajax央浼获取REST服务的能源。

让Web API以CamelCase输出JSON

在Global.asax文件中增加以下几行代码:

var formatters = GlobalConfiguration.Configuration.Formatters;
var jsonFormatter = formatters.JsonFormatter;
var settings = jsonFormatter.SerializerSettings;
settings.Formatting = Formatting.Indented;
settings.ContractResolver = new CamelCasePropertyNamesContractResolver();

亚洲城ca88 21

可是REST
瑟维Stone常是被设计为无状态的(Stateless),那意味着大家不能够凭仗于Session来保存顾客音信,也不可能使用Session[“UserID”]这种方法明确顾客身份。

启用CORS

在Nuget Package Manager Console输入以下命令:

Install-Package Microsoft.AspNet.WebApi.Cors

在WebApiConfig中启用CORS:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        var cors = new EnableCorsAttribute("*", "*", "*");
        config.EnableCors(cors);

        // ...

    }
}

输入客商名和密码就能够获取token

化解这些难题的章程是如何吧?常规的措施是行使OAuth 2.0。

类说明

在试行上述手续时,VS已经帮大家转移好了某些类

亚洲城ca88 22

IdentityModels.cs:包蕴ApplicationDbContext类和ApplicationUser类,无需更创设DbContext类

public class ApplicationUser : IdentityUser
{
    // ...
}

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    // ...
}

Startup.Auth.cs:用于配置OAuth的有些属性。

public partial class Startup
{
    public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }

    public static string PublicClientId { get; private set; }

    // For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
    public void ConfigureAuth(IAppBuilder app)
    {
        // ..

        // Configure the application for OAuth based flow
        PublicClientId = "self";
        OAuthOptions = new OAuthAuthorizationServerOptions
        {
            TokenEndpointPath = new PathString("/Token"),
            Provider = new ApplicationOAuthProvider(PublicClientId),
            AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
            // In production mode set AllowInsecureHttp = false
            AllowInsecureHttp = true
        };

        // Enable the application to use bearer tokens to authenticate users
        app.UseOAuthBearerTokens(OAuthOptions);

        // ..
    }
}

这一个OAuth配置项,大家只用关爱个中的两项:

  • TokenEndpoint帕特h:表示顾客端发送验证伏乞的地方,例如:Web
    API的站点为www.example.com,验证须要的地点则为www.example.com/token。
  • UseOAuthBearerTokens:使用Bearer类型的token_type(令牌类型)。

ApplicationOAuthProvider.cs:默认的OAuthProvider实现,GrantResourceOwnerCredentials方法用于申明客户身份新闻,并赶回access_token(访谈令牌)。

public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
   // ...     
}

初叶地讲,客商端输入客商名、密码,点击登入后,会发起呼吁到www.example.com/token。
token那些恳求在服务端推行的求证措施是何许啊?正是GrantResourceOwnerCredentials方法。

顾客端发起验证恳求时,必然是跨域的,token那几个央浼不属于别的ApiController的Action,而在WebApiConfig.cs中启用全局的COLacrosseS,只对ApiController有效,对token乞请是不起功效的。
为此还亟需在GrantResourceOwnerCredentials方法中增加一行代码:

public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
    context.Response.Headers.Add("Access-Control-Allow-Origin", new []{"*"});
    // ...
}

IdentityConfig.cs:配置客商名和密码的复杂度,首要用来客商注册时。比方:分裂意客商名字为纯字母和数字的组成,密码长度起码为6位…。

亚洲城ca88 23 遮掩代码

public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
    var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
    // Configure validation logic for usernames
    manager.UserValidator = new UserValidator<ApplicationUser>(manager)
    {
        AllowOnlyAlphanumericUserNames = false,
        RequireUniqueEmail = true
    };
    // Configure validation logic for passwords
    manager.PasswordValidator = new PasswordValidator
    {
        RequiredLength = 6,
        RequireNonLetterOrDigit = true,
        RequireDigit = true,
        RequireLowercase = true,
        RequireUppercase = true,
    };
    // ...
    return manager;
}

亚洲城ca88 24

对此客户相关的OpenAPI,为了有限支撑顾客数据的防城港和隐秘,第三方Web应用访问客商数据前都亟需显式的向客商征求授权。
比较于OAuth 1.0,OAuth 2.0的印证流程进一步简便易行。

使用Postman测试GET和POST请求

测试GET请求

亚洲城ca88 25

GET央求测量试验成功,能够得到到JSON数据。

测试POST请求

亚洲城ca88 26

POST乞求测量试验不经过,提醒:验证不通过,央求被驳回。

获取结果,注意选取时前边加上 Bearer + 空格

专项使用名词介绍

依赖$.ajax达成登记、登入、注销和API调用

服务端的条件已经希图好了,现在大家就各个落到实处客商注册、登入,以及API调用功用吗。

亚洲城ca88 27

在掌握OAuth 2.0以前,大家先精通多少个名词:

注册

页面包车型客车HTML代码如下:

<div id="app">
    <div class="container">
        {{ msg }}
    </div>
    <div class="container">
            <div class="form-group">
                <label>电子邮箱</label>
                <input type="text" v-model="registerModel.email" />
            </div>
            <div class="form-group">
                <label>密码</label>
                <input type="text" v-model="registerModel.password" />
            </div>

            <div class="form-group">
                <label>确认密码</label>
                <input type="text" v-model="registerModel.confirmPassword" />
            </div>

            <div class="form-group">
                <label></label>
                <button @click="register">注册</button>
            </div>
    </div>
</div>

制造Vue实例,然后遵照$.ajax发送顾客注册央浼:

var demo = new Vue({
    el: '#app',
    data: {
        registerUrl: 'http://localhost:10648/api/Account/Register',
        registerModel: {
            email: '',
            password: '',
            confirmPassword: ''
        },
        msg: ''
    },
    methods: {
        register: function() {
            var vm = this
            vm.msg = ''

            $.ajax({
                url: vm.registerUrl,
                type: 'POST',
                dataType: 'json',
                data: vm.registerModel,
                success: function() {
                    vm.msg = '注册成功!'
                },
                error: vm.requestError
            })
        },
        requestError: function(xhr, errorType, error) {
            this.msg = xhr.responseText
        }
    }
})

亚洲城ca88 28

View
Demo

解决方案二:

  1. Resource:能源,和REST中的财富概念同样,某些能源是采访受有限支撑的
  2. Resource Server:贮存财富的服务器
  3. Resource Owner:财富全部者,本文中又称为客户(user)
  4. User Agent:客户代理,即浏览器
  5. Client: 访谈财富的客商端,也正是应用程序
  6. Authorization Server:认证服务器,用于给Client提供访谈令牌的服务器
  7. Access Token:访谈能源的令牌,由Authorization
    Server器授予,Client访问Resource时,需提供Access Token
  8. Bearer Token:Bearer Token是Access Token的一种,另一种是Mac Token。
  9. Bearer Token的运用格式为:Bearer XXXXXXXX

报到和收回

登录的HTML代码:

<div id="app">
    <div class="container text-center">
        {{ msg }}
    </div>
    <div class="container">
        <div class="account-info">
            {{ userName }} | <a href="#" @click="logout">注销</a>
        </div>
    </div>
    <div class="container">
            <div class="form-group">
                <label>电子邮箱</label>
                <input type="text" v-model="loginModel.username" />
            </div>
            <div class="form-group">
                <label>密码</label>
                <input type="text" v-model="loginModel.password" />
            </div>
            <div class="form-group">
                <label></label>
                <button @click="login">登录</button>
            </div>
    </div>
</div>

开创Vue实例,然后依照$.ajax发送客商登入央浼:

var demo = new Vue({
    el: '#app',
    data: {
        loginUrl: 'http://localhost:10648/token',
        logoutUrl: 'http://localhost:10648/api/Account/Logout',
        loginModel: {
            username: '',
            password: '',
            grant_type: 'password'
        },
        msg: '',
        userName: ''
    },

    ready: function() {
        this.userName = sessionStorage.getItem('userName')
    },
    methods: {
        login: function() {
            var vm = this
                vm.msg = ''
                vm.result = ''

            $.ajax({
                url: vm.loginUrl,
                type: 'POST',
                dataType: 'json',
                data: vm.loginModel,
                success: function(data) {
                    vm.msg = '登录成功!'
                    vm.userName = data.userName
                    sessionStorage.setItem('accessToken', data.access_token)
                    sessionStorage.setItem('userName', vm.userName)
                },
                error: vm.requestError
            })
        },
        logout: function() {
            var vm = this
                vm.msg = ''

            $.ajax({
                url: vm.logoutUrl,
                type: 'POST',
                dataType: 'json',
                success: function(data) {

                    vm.msg = '注销成功!'
                    vm.userName = ''
                    vm.loginModel.userName = ''
                    vm.loginModel.password = ''

                    sessionStorage.removeItem('userName')
                    sessionStorage.removeItem('accessToken')
                },
                error: vm.requestError
            })
        },
        requestError: function(xhr, errorType, error) {
            this.msg = xhr.responseText
        }
    }
})

亚洲城ca88 29

View
Demo

在试验那一个示例时,把Fiddler也开拓,我们总括进行了3次操作:

  1. 第1次操作:输入了错误的密码,服务端响应400的状态码,并提示了错误音信。
  2. 第2次操作:输入了正确的用户名和密码,服务端响应200的状态码
  3. 第3次操作:点击右上角的吊销链接

亚洲城ca88 30

注意第2次操作,在Fiddler中查看服务端再次回到的从头到尾的经过:

亚洲城ca88 31

服务端重回了access_token, expires_in, token_type,userName等新闻,在客户端能够用sessionStoragelocalStorage保存access_token

大家得以一贯登入顾客端查看访谈API的token值就可以

Token的类型请参见:

调用API

取到了access_token后,大家就能够基于access_token去探访服务端受保险的财富了。
这里大家要拜候的财富是/api/Values,它出自ValuesController的Get操作。

依据注册画面,增添一段HTML代码:

<div class="container text-center">
    <div>
        <button @click="callApi">调用API</button>
    </div>
    <div class="result">
        API调用结果:{{ result | json }}
    </div>
</div>

在Vue实例中增添贰个callApi方法:

callApi: function() {
    var vm = this
        vm.msg = ''
        vm.result = ''

        headers = {}
        headers.Authorization = 'Bearer ' + sessionStorage.getItem('accessToken');

    $.ajax({
        type: 'get',
        dataTye: 'json',
        url: vm.apiUrl,
        headers: headers,
        success: function(data) {
            vm.result = data
        },
        error: vm.requestError
    })
}

在调用callApi方法时,设置了伏乞头的Authorization属性,其格式为:"Bearer access_token"
出于服务端钦点使用了Bearer体系的access
token,所以客商端必需利用这种格式将access token传给财富服务器。

亚洲城ca88 32

View
Demo

在考试这几个示例时,大家总共举办了5次操作:

  1. 第1次操作:未有输入顾客名和密码,间接点击[调用API]开关,服务端再次回到401的状态码,表示该央浼未授权。
  2. 第2次操作:输入客户名和密码,然后店点击登陆开关,登入成功。
  3. 第3次操作:点击[调用API]按键,服务端重临200的状态码,供给成功。
  4. 第4次操作:点击[注销]链接,注销成功。
  5. 第5次操作:再一次点击[调用API]按键,服务端重回401的状态码,表示该央求未授权。

亚洲城ca88 33

有人可能会小心到,为何历次点击[调用API]按键,都倡导了一遍呼吁?

那是因为当浏览器发送跨域必要时,浏览器都会首发送叁个OPTIONS预央浼(preflight
request)给目的站点,用于确认目的站点是不是接受跨域央求,借使指标站点不协理跨域央求,浏览器会提醒错误:No 'Access-Control-Allow-Origin' header is present on the requested resource.

假定是POST乞请,且数据类型(Content-Type)是
application/x-www-form-urlencoded,multipart/form-data 或 text/plain中的一种,则浏览器不会发送预诉求,上海教室的/token恳求正是满意该原则的。

zepto会自动将非GET央求的Content-Type设置为application/x-www-form-urlencoded

if (settings.contentType || (settings.contentType !== false && settings.data && settings.type.toUpperCase() != 'GET'))
  setHeader('Content-Type', settings.contentType || 'application/x-www-form-urlencoded')

亚洲城ca88 34

小编们还是通过Fidder看一下第1次/api/Values需要和响应的Headers音信

恳请的Headers消息,它是叁遍OPTIONS请求。

亚洲城ca88 35

响应的Headers信息,Access-Control-Allow-Origin: *代表同意具有外界站点对指标站点发送跨域央浼。

亚洲城ca88 36

越多CO传祺S的文化,请参见MDN上的表明:

本身以admin登陆成功后,F12
查看浏览器访问后台token值,在Network下随意点击三个呼吁数据到后台央浼API的链接(注:作者用的是谷歌(Google)chrome 浏览器)

突发性认证服务器和能源服务器能够是一台服务器,本文中的Web
API示例就是这种应用境况。

依靠vue-resource完结登记、登陆和API调用

依照vue-resource完毕那3项职能时,沿用上边的HTML代码。

 亚洲城ca88 37

OAuth认证流程

注册

进一步精简的register方法:

register: function() {
    this.$http.post(this.registerUrl, this.registerModel)
        .then((response) => {
            this.msg = '注册成功!'
        }).catch((response) => {
            this.msg = response.json()
        })
}

View
Demo

注意:当使用vue-resource发送注册的POST乞求时,Fiddler捕获到了2次呼吁,第1次是由浏览器发送的OPTIONS预伏乞,第2次才是事实上的POST诉求。那和平运动用$.ajax时是不等同的,因为$.ajax会将非GET央浼的Content-Type设置为application/x-www-form-urlencoded,而vue-resource发送POST请求的Content-Type为application/json;charset=UTF-8

大家在上头的Headers的Request
Headers里面包车型客车Authorization查见到授权token音讯

在明亮这些词今后,我们用这多少个名词来编个旧事。

亚洲城ca88 38

亚洲城ca88 39

启用emulateJSON选项,能够让浏览器不发送OPTIONS预央浼,有二种启用形式。

1.全局启用

Vue.http.options.emulateJSON = true

2.片段启用

this.$http.post(this.registerUrl, this.registerModel ,{ emulateJSON : true})
    .then( (response) => {
        this.msg = '注册成功!'
    })

启用了emulateJSON选项后,使得POST请求的Content-Type变为application/x-www-form-urlencoded

Bearer
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjIiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiYWRtaW4iLCJBc3BOZXQuSWRlbnRpdHkuU2VjdXJpdHlTdGFtcCI6IjY3NDhlNDQ2LTI4YWUtYWRjNi0zNmU2LTM5ZTIzMGFhNzA3MSIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvcm9sZSI6IkFkbWluIiwiaHR0cDovL3d3dy5hc3BuZXRib2lsZXJwbGF0ZS5jb20vaWRlbnRpdHkvY2xhaW1zL3RlbmFudElkIjoiMSIsInN1YiI6IjIiLCJqdGkiOiI0N2U0Y2YwNC05ODYyLTQ4MjItOTBhOC01Njk1NWUwYWE1M2UiLCJpYXQiOjE1MTE0NDU3MjUsIm5iZiI6MTUxMTQ0NTcyNSwiZXhwIjoxNTExNTMyMTI1LCJpc3MiOiJzYWFzIiwiYXVkIjoic2FhcyJ9.eXDes4LNkV4dkcFy-GTSF6kGDTK3a0blS3I6O7c2HuQ

简化版本

亚洲城ca88 40

将那些授权音信copy到我们后台实行授权

本条传说的简化版本是:客商(Resource Owner)访谈财富(Resource)。

登入和撤回

报到和撤废的章程:

login: function() {

    this.$http.post(this.loginUrl, this.loginModel)
        .then((response) => {
            var body = response.json()
            this.msg = '登录成功!'
            this.userName = body.userName

            sessionStorage.setItem('accessToken', body.access_token)
            sessionStorage.setItem('userName', body.userName)

        }).catch(this.requestError)
},
logout: function() {

    this.$http.post(this.logoutUrl)
        .then((response) => {
            this.msg = '注销成功!'
            this.userName = ''
            this.loginModel.username = ''
            this.loginModel.password = ''

            sessionStorage.removeItem('userName')
            sessionStorage.removeItem('accessToken')

        }).catch(this.requestError)
},
requestError: function(response) {
    this.msg = response.json()
}

View
Demo

 亚洲城ca88 41

亚洲城ca88 42

API调用

调用API的艺术也更为精简:

callApi: function() {

    var headers = {}
    headers.Authorization = 'Bearer ' + sessionStorage.getItem('accessToken')

    this.$http.get(this.apiUrl, {
            headers: headers
        })
        .then((response) => {
            this.result = response.json()
        }).catch(this.requestError)
}

同样的,在发送央求前,需求将access token加多到央浼头。

View
Demo

 

切实版本

汇总示范

本文在预备服务端遇到的时候,提供了一个CustomersController,除了GET操作,其余操作的拜候都以受保障的,须求客商登陆未来本事操作。

现行反革命我们来促成这几个示例,
该示例结合了上一篇的CU奇骏D示例,以及本文的登记、登陆、注销功用。

切切实实代码小编就不再贴出来了,我们结合源代码试一试呢。

亚洲城ca88 43

View
Demo

再点成本现已授权成功

简化版的遗闻独有二个结实,上面是其一传说的切实版本:

 亚洲城ca88 44

  1. 顾客通过浏览器展开客商端后,客商端供给顾客给予授权。
  2. 客户端能够一贯将授权央求发给客户(如图所示),可能发送给叁个中等媒介,举例认证服务器。
  3. 顾客同意给予客商端授权,客商端收到客户的授权。
  4. 授权方式(GrantType)决议于客商端选择的情势,以及表明服务器所协理的形式。
  5. 客商端提供身份消息,然后向认证服务器发送央浼,申请访谈令牌
  6. 注脚服务器验证客户端提供的地方新闻,借使注脚通过,则向顾客端发放令牌
  7. 顾客端采取访谈令牌,向能源服务器要求受保证的财富
  8. 财富服务器验证访谈令牌,假设可行,则向客商端开放财富

然后大家再实行测量试验,Response
Code已回到200,测量试验通过。在后台打断点就可以调整

亚洲城ca88 45

 亚洲城ca88 46

上述多少个步骤,(B)是相当的重大的多少个,即顾客怎么样技艺给顾客端授权。有了那么些授权以后,顾客端就能够得到令牌,进而通过临牌获取财富。这也是OAuth
2.0的运作流程,实际情况请仿效:

 

顾客端的授权形式

客户端必需得到客户的授权(authorization grant),技术获得令牌(access
token)。

OAuth 2.0概念了三种授权格局:

  1. 授权码方式(authorization code)
  2. 简化方式(implicit)
  3. 密码情势(resource owner password credentials)
  4. 客商端形式(client credentials)

正文的亲自去做是基于密码方式的,笔者就只简介这种方式,别的3自家就不介绍了。

密码方式

密码格局(Resource Owner Password Credentials
Grant)中,顾客向客商端提供温馨的顾客名和密码。客户端应用那几个新闻,向服务端申请授权。

在这种方式中,客户必得把本人的密码给顾客端,不过客商端不可存款和储蓄密码。那经常用在客户对顾客端中度信任的情形下,比方客商端是操作系统的一有个别,大概由二个名满天下公司出品。

亚洲城ca88 47

密码嘛事的进行步骤如下:

(A)客户向顾客端提供客户名和密码。

(B)客商端将顾客名和密码发给认证服务器,向前者乞求令牌。

(C)认证服务器确认正确后,向顾客端提供访谈令牌。

(B)步骤中,客商端发出的HTTP央求,满含以下参数:

  1. grant_type:表示授权类型,此处的值固定为”password”,必选项。
  2. username:表示客户名,必选项。
  3. password:表示客户的密码,必选项。
  4. scope:表示权限限制,可选项。

只顾:在背后的客商端示例中,除了提供username和password,grant_type也是必得钦定为”password”,不然无法获得服务端的授权。

服务端蒙受打算

一经你是前端开拓职员,并且未接触过ASP.Net Web API,可以跳过此段子。

亚洲城ca88 48

Authentication选择Individual User Accounts

亚洲城ca88 49

成立这几个Web API工程时,VS会活动引进Owin和AspNet.Identity相关的库。

亚洲城ca88 50

修改ValuesController,除了IEnumerable<string>
Get()操作外,其余操作都剔除,并为该操作使用[Authorize]特色,那意味着顾客端必得通过身份验证后才干调用该操作。

public class ValuesController : ApiController
{
  // GET: api/Values
  [Authorize]
  public IEnumerable<string> Get()
  {
    return new string[] { "value1", "value2" };
  }
}

添加Model, Controller

亚洲城ca88 51

亚洲城ca88 52

亚洲城ca88 53

早先化数据库

亚洲城ca88 54

实施以下3个指令

亚洲城ca88 55

亚洲城ca88 56

CustomersController类有5个Action,除了2个GET需要外,别的3个央浼分别是POST,
PUT和DELETE。
为那3个伏乞增添[Authorize]特点,那3个乞求必得经过身份验证才干访谈。

public class CustomersController : ApiController
{
  private ApplicationDbContext db = new ApplicationDbContext();

  // GET: api/Customers
  public IQueryable<Customer> GetCustomers()
  {
    return db.Customers;
  }

  // GET: api/Customers/5
  [ResponseType(typeof(Customer))]
  public async Task<IHttpActionResult> GetCustomer(int id)
  {
    Customer customer = await db.Customers.FindAsync(id);
    if (customer == null)
    {
      return NotFound();
    }

    return Ok(customer);
  }

  // PUT: api/Customers/5
  [Authorize]
  [ResponseType(typeof(void))]
  public async Task<IHttpActionResult> PutCustomer(int id, Customer customer)
  {
   // ...
  }

  // POST: api/Customers
  [Authorize]
  [ResponseType(typeof(Customer))]
  public async Task<IHttpActionResult> PostCustomer(Customer customer)
  {
    // ...
  }

  // DELETE: api/Customers/5
  [ResponseType(typeof(Customer))]
  [Authorize]
  public async Task<IHttpActionResult> DeleteCustomer(int id)
  {
   // ...
  }
}

让Web API以CamelCase输出JSON

在Global.asax文件中增进以下几行代码:

var formatters = GlobalConfiguration.Configuration.Formatters;
var jsonFormatter = formatters.JsonFormatter;
var settings = jsonFormatter.SerializerSettings;
settings.Formatting = Formatting.Indented;
settings.ContractResolver = new CamelCasePropertyNamesContractResolver();

启用CORS

在Nuget Package Manager Console输入以下命令:

Install-Package Microsoft.AspNet.WebApi.Cors

在WebApiConfig中启用CORS:

public static class WebApiConfig
{
  public static void Register(HttpConfiguration config)
  {
    var cors = new EnableCorsAttribute("*", "*", "*");
    config.EnableCors(cors);

    // ...

  }
}

类说明

在试行上述手续时,VS已经帮大家调换好了某些类

亚洲城ca88 57

IdentityModels.cs:包罗ApplicationDbContext类和ApplicationUser类,没有须要再次创下制DbContext类

public class ApplicationUser : IdentityUser
{
  // ...
}

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
  // ...
}

Startup.Auth.cs:用于配置OAuth的部分性质。

public partial class Startup
{
  public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }

  public static string PublicClientId { get; private set; }

  // For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
  public void ConfigureAuth(IAppBuilder app)
  {
    // ..

    // Configure the application for OAuth based flow
    PublicClientId = "self";
    OAuthOptions = new OAuthAuthorizationServerOptions
    {
      TokenEndpointPath = new PathString("/Token"),
      Provider = new ApplicationOAuthProvider(PublicClientId),
      AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
      AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
      // In production mode set AllowInsecureHttp = false
      AllowInsecureHttp = true
    };

    // Enable the application to use bearer tokens to authenticate users
    app.UseOAuthBearerTokens(OAuthOptions);

    // ..
  }
}

那个OAuth配置项,大家只用关爱在那之中的两项:

  1. TokenEndpointPath:表示客商端发送验证伏乞的地方,比方:Web
    API的站点为www.example.com,验证央浼的地方则为www.example.com/token。
  2. UseOAuthBearerTokens:使用Bearer类型的token_type(令牌类型)。

ApplicationOAuthProvider.cs:私下认可的OAuthProvider完毕,GrantResourceOwnerCredentials方法用于申明客户身份音信,并回到access_token(访问令牌)。

public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
  // ...   
}

浅显地讲,顾客端输入客商名、密码,点击登入后,会倡导呼吁到www.example.com/token。

token这一个诉求在服务端推行的认证办法是怎么样吗?就是GrantResourceOwnerCredentials方法。

客商端发起验证央求时,必然是跨域的,token那些央求不属于其余ApiController的Action,而在WebApiConfig.cs中启用全局的CO途乐S,只对ApiController有效,对token央浼是不起效用的。
故而还索要在GrantResourceOwnerCredentials方法中添加一行代码:

public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
  context.Response.Headers.Add("Access-Control-Allow-Origin", new []{"*"});
  // ...
}

IdentityConfig.cs:配置客户名和密码的复杂度,首要用于顾客注册时。举个例子:不容许客户名字为纯字母和数字的整合,密码长度起码为6位…。

public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
  var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
  // Configure validation logic for usernames
  manager.UserValidator = new UserValidator<ApplicationUser>(manager)
  {
    AllowOnlyAlphanumericUserNames = false,
    RequireUniqueEmail = true
  };
  // Configure validation logic for passwords
  manager.PasswordValidator = new PasswordValidator
  {
    RequiredLength = 6,
    RequireNonLetterOrDigit = true,
    RequireDigit = true,
    RequireLowercase = true,
    RequireUppercase = true,
  };
  // ...
  return manager;
}

使用Postman测试GET和POST请求

测试GET请求

亚洲城ca88 58

GET需要测量试验成功,能够取获得JSON数据。

测试POST请求

亚洲城ca88 59

POST央浼测量检验不经过,提醒:验证不通过,须要被拒绝。

基于$.ajax实现登记、登陆、注销和API调用

服务端的情况已经打算好了,未来大家就每个达成客商注册、登入,以及API调用功效吗。

注册

页面包车型大巴HTML代码如下:

<div id="app">
  <div class="container">
    {{ msg }}
  </div>
  <div class="container">
      <div class="form-group">
        <label>电子邮箱</label>
        <input type="text" v-model="registerModel.email" />
      </div>
      <div class="form-group">
        <label>密码</label>
        <input type="text" v-model="registerModel.password" />
      </div>

      <div class="form-group">
        <label>确认密码</label>
        <input type="text" v-model="registerModel.confirmPassword" />
      </div>

      <div class="form-group">
        <label></label>
        <button @click="register">注册</button>
      </div>
  </div>
</div>

始建Vue实例,然后依照$.ajax发送客户注册哀告:

var demo = new Vue({
  el: '#app',
  data: {
    registerUrl: 'http://localhost:10648/api/Account/Register',
    registerModel: {
      email: '',
      password: '',
      confirmPassword: ''
    },
    msg: ''
  },
  methods: {
    register: function() {
      var vm = this
      vm.msg = ''

      $.ajax({
        url: vm.registerUrl,
        type: 'POST',
        dataType: 'json',
        data: vm.registerModel,
        success: function() {
          vm.msg = '注册成功!'
        },
        error: vm.requestError
      })
    },
    requestError: function(xhr, errorType, error) {
      this.msg = xhr.responseText
    }
  }
})

亚洲城ca88 60

登陆和注销

登录的HTML代码:

<div id="app">
  <div class="container text-center">
    {{ msg }}
  </div>
  <div class="container">
    <div class="account-info">
      {{ userName }} | <a href="#" rel="external nofollow" @click="logout">注销</a>
    </div>
  </div>
  <div class="container">
      <div class="form-group">
        <label>电子邮箱</label>
        <input type="text" v-model="loginModel.username" />
      </div>
      <div class="form-group">
        <label>密码</label>
        <input type="text" v-model="loginModel.password" />
      </div>
      <div class="form-group">
        <label></label>
        <button @click="login">登录</button>
      </div>
  </div>
</div>

始建Vue实例,然后依照$.ajax发送客户登入恳求:

var demo = new Vue({
  el: '#app',
  data: {
    loginUrl: 'http://localhost:10648/token',
    logoutUrl: 'http://localhost:10648/api/Account/Logout',
    loginModel: {
      username: '',
      password: '',
      grant_type: 'password'
    },
    msg: '',
    userName: ''
  },

  ready: function() {
    this.userName = sessionStorage.getItem('userName')
  },
  methods: {
    login: function() {
      var vm = this
        vm.msg = ''
        vm.result = ''

      $.ajax({
        url: vm.loginUrl,
        type: 'POST',
        dataType: 'json',
        data: vm.loginModel,
        success: function(data) {
          vm.msg = '登录成功!'
          vm.userName = data.userName
          sessionStorage.setItem('accessToken', data.access_token)
          sessionStorage.setItem('userName', vm.userName)
        },
        error: vm.requestError
      })
    },
    logout: function() {
      var vm = this
        vm.msg = ''

      $.ajax({
        url: vm.logoutUrl,
        type: 'POST',
        dataType: 'json',
        success: function(data) {

          vm.msg = '注销成功!'
          vm.userName = ''
          vm.loginModel.userName = ''
          vm.loginModel.password = ''

          sessionStorage.removeItem('userName')
          sessionStorage.removeItem('accessToken')
        },
        error: vm.requestError
      })
    },
    requestError: function(xhr, errorType, error) {
      this.msg = xhr.responseText
    }
  }
})

亚洲城ca88 61

在侦察那几个示例时,把Fiddler也开荒,大家一共进行了3次操作:

  1. 第1次操作:输入了错误的密码,服务端响应400的状态码,并提示了错误音讯。
  2. 第2次操作:输入了不易的顾客名和密码,服务端响应200的状态码
  3. 第3次操作:点击右上角的撤除链接

亚洲城ca88 62

瞩目第2次操作,在Fiddler中查阅服务端重返的原委:

亚洲城ca88 63

服务端再次来到了access_token, expires_in,
token_type,userName等音信,在顾客端能够用sessionStorage或localStorage保存access_token。

调用API

取到了access_token后,大家就能够基于access_token去拜望服务端受保障的能源了。

此间大家要访谈的财富是/api/Values,它出自ValuesController的Get操作。

好玩的事注册画面,添加一段HTML代码:

<div class="container text-center">
  <div>
    <button @click="callApi">调用API</button>
  </div>
  <div class="result">
    API调用结果:{{ result | json }}
  </div>
</div>

在Vue实例中增多三个callApi方法:

callApi: function() {
  var vm = this
    vm.msg = ''
    vm.result = ''

    headers = {}
    headers.Authorization = 'Bearer ' + sessionStorage.getItem('accessToken');

  $.ajax({
    type: 'get',
    dataTye: 'json',
    url: vm.apiUrl,
    headers: headers,
    success: function(data) {
      vm.result = data
    },
    error: vm.requestError
  })
}

在调用callApi方法时,设置了乞求头的Authorization属性,其格式为:”Bearer
access_token”。
是因为服务端钦赐使用了Bearer类型的access
token,所以客商端必需使用这种格式将access token传给能源服务器。

亚洲城ca88 64

在试验这一个示例时,大家一共实行了5次操作:

  1. 第1次操作:未有输入客商名和密码,直接点击[调用API]按键,服务端再次回到401的状态码,表示该央求未授权。
  2. 第2次操作:输入客商名和密码,然后店点击登陆按键,登陆成功。
  3. 第3次操作:点击[调用API]开关,服务端再次回到200的状态码,央求成功。
  4. 第4次操作:点击[注销]链接,注销成功。
  5. 第5次操作:再一次点击[调用API]开关,服务端重临401的状态码,表示该央求未授权。

亚洲城ca88 65

有人可能会小心到,为何老是点击[调用API]按键,都提倡了四遍呼吁?

那是因为当浏览器发送跨域乞求时,浏览器都会头阵送贰个OPTIONS预诉求(preflight
request)给目的站点,用于确认目的站点是不是接受跨域乞求,即便指标站点不帮助跨域乞请,浏览器会提示错误:

No 'Access-Control-Allow-Origin' header is present on the requested resource.

一经是POST央浼,且数据类型(Content-Type)是application/x-www-form-urlencoded,multipart/form-data

text/plain中的一种,则浏览器不会发送预央求,上海体育场合的/token央求便是满意该标准的。

zepto会自动将非GET伏乞的Content-Type设置为application/x-www-form-urlencoded

if (settings.contentType || (settings.contentType !== false && settings.data && settings.type.toUpperCase() != 'GET'))
 setHeader('Content-Type', settings.contentType || 'application/x-www-form-urlencoded')
image

我们如故通过Fidder看一下第1次/api/Values央求和响应的Headers音讯

呼吁的Headers消息,它是三遍OPTIONS乞请。

亚洲城ca88 66

响应的Headers信息,Access-Control-Allow-Origin:
*意味着同意持有外界站点对目的站点发送跨域乞求。

亚洲城ca88 67

越多COEscortS的知识,请参照他事他说加以考察MDN上的证实:

依附vue-resource达成挂号、登陆和API调用

基于vue-resource达成那3项作用时,沿用下边包车型客车HTML代码。

注册

更是精简的register方法:

register: function() {
  this.$http.post(this.registerUrl, this.registerModel)
    .then((response) => {
      this.msg = '注册成功!'
    }).catch((response) => {
      this.msg = response.json()
    })
}

静心:当使用vue-resource发送注册的POST央求时,Fiddler捕获到了2次呼吁,第1次是由浏览器发送的OPTIONS预乞请,第2次才是实际上的POST央求。那和采纳$.ajax时是不等同的,因为$.ajax会将非GET央求的Content-Type设置为application/x-www-form-urlencoded,而vue-resource发送POST央浼的Content-Type为application/json;charset=UTF-8。

亚洲城ca88 68

亚洲城ca88 69

启用emulateJSON选项,能够让浏览器不发送OPTIONS预供给,有二种启用方式。

1.全局启用

Vue.http.options.emulateJSON = true

2.局地启用

this.$http.post(this.registerUrl, this.registerModel ,{ emulateJSON : true})
  .then( (response) => {
    this.msg = '注册成功!'
  })

启用了emulateJSON选项后,使得POST请求的Content-Type变为application/x-www-form-urlencoded

亚洲城ca88 70

签到和裁撤

签到和收回的不二法门:

login: function() {

  this.$http.post(this.loginUrl, this.loginModel)
    .then((response) => {
      var body = response.json()
      this.msg = '登录成功!'
      this.userName = body.userName

      sessionStorage.setItem('accessToken', body.access_token)
      sessionStorage.setItem('userName', body.userName)

    }).catch(this.requestError)
},
logout: function() {

  this.$http.post(this.logoutUrl)
    .then((response) => {
      this.msg = '注销成功!'
      this.userName = ''
      this.loginModel.username = ''
      this.loginModel.password = ''

      sessionStorage.removeItem('userName')
      sessionStorage.removeItem('accessToken')

    }).catch(this.requestError)
},
requestError: function(response) {
  this.msg = response.json()
}

API调用

调用API的法子也尤其精简:

callApi: function() {

  var headers = {}
  headers.Authorization = 'Bearer ' + sessionStorage.getItem('accessToken')

  this.$http.get(this.apiUrl, {
      headers: headers
    })
    .then((response) => {
      this.result = response.json()
    }).catch(this.requestError)
}

一致的,在发送诉求前,必要将access token增多到央浼头。

归结示范

正文在备选服务端境况的时候,提供了多少个CustomersController,除了GET操作,其余操作的探问都以受保证的,供给客户登陆以往能力操作。

当今大家来兑现这些示例,
该示例结合了上一篇的CULX570D示例,以及本文的挂号、登入、注销成效。

具体代码我就不再贴出来了,我们结合源代码试一试呢。

亚洲城ca88 71

上述便是本文的全体内容,希望对大家的读书抱有利于,也盼望大家多多指教脚本之家。

您只怕感兴趣的篇章:

  • Vue.js完结叁个SPA登陆页面包车型大巴经过【推荐】
  • vue.js实现客商评价、登陆、注册、及修改音信作用
  • 选用Vue.js和Element-UI做三个简短登陆页面包车型大巴实例
  • 依照 Vue.js 2.0
    炫耀自适应背景录像登陆页面达成格局
  • Vue.js达成可配备的登入表单代码详解
  • Vue学习之路之登陆注册实例代码
  • vue路由跳转时判定客户是不是登陆成效的贯彻
  • 详解Vuex管理登入情状
  • Vue中保存顾客登入状态实例代码
  • vue.js中贯彻登陆调节的办法亲自过问

相关文章