WebApi基於令牌的簡述和應用

我們知道WEB網站的身份驗證一般通過session或者cookie完成的,登錄成功後客戶端發送的任何請求都帶上cookie,服務端根據客戶端發送來的cookie來識別用戶。然而在WebAPI中,我們採用類似的方式,帶有驗證的令牌模式,方便移動端和項目內部調用,能夠解耦合,便於維護,可擴展延伸。

一、OAuth簡介

1、什麼是OAuth
OAuth是一個關於授權(Authorization)的開放網絡標準,目前的版本是2.0版。注意是Authorization(授權),而不是Authentication(認證)。用來做Authentication(認證)的標準叫做openid connect,我們將在以後的文章中進行介紹。
2、名詞定義
理解OAuth中的專業術語能夠幫助你理解其流程模式,OAuth中常用的名詞術語有4個,爲了便於理解這些術語,我們先假設一個很常見的授權場景:
你訪問了一個日誌網站(third party application),你(client)覺得這個網站很不錯,準備以後就要在這個網站上寫日誌了,所以你準備把QQ空間(Resource owner)裏面的日誌都導入進來。此日誌網站想要導入你在QQ空間中的日誌需要知道你的QQ用戶名和密碼才行,爲了安全期間你不會把你的QQ用戶名和密碼直接輸入在日誌網站中,所以日誌網站幫你導航到了QQ認證界面(Authorization Server),當你輸入完用戶名和密碼後,QQ認證服務器返回給日誌網站一個token, 該日誌網站憑藉此token來訪問你在QQ空間中的日誌。
1) third party application 第三方的應用,想要的到Resource owner的授權
2) client 代表用戶
3) Resource owner 資源擁有者,在這裏代表QQ
4) Authorization server 認證服務,這裏代表QQ認證服務,Resource owner和Authorization server可以是不同的服務器,也可以是同一個服務器。
3、OAuth2.0中的四種模式
OAuth定義了四種模式,覆蓋了所有的授權應用場景:
1) 授權碼模式(authorization code)
2) 簡化模式(implicit)
3) 密碼模式(resource owner password credentials)
4) 客戶端模式(client credentials)
前面我們假設的場景可以用前兩種模式來實現,不同之處在於:
當日志網站(third party application)有服務端,使用模式1;
當日志網站(third party application)沒有服務端,例如純的js+html頁面需要採用模式2;
本文主描述利用OAuth2.0實現自己的WebApi認證服務,前兩種模式使用場景不符合我們的需求。

二、基於令牌的認證和應用

1、需要安裝的工具:postman-4.1.2
可以百度安裝postman,如下是非官方安裝,便捷操作
1)下載地址:
鏈接:https://pan.baidu.com/s/1r0gyqrkd5Gp6MwEN9GEG8w
提取碼:ridq
2)、安裝步驟
(1)、打開谷歌瀏覽器設置
在這裏插入圖片描述
(2)、打開指定目錄,添加就可以了
在這裏插入圖片描述
2、簡述創建項目
1)、第一步,創建WebAPI空項目
在這裏插入圖片描述
在這裏插入圖片描述
2)、第二步在Model目錄下添加Student類

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Super.WebApi.Models
{
    public class Student
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
    }
}

3)、第三步在Controllers目錄下添加StudentsController類

using Super.WebApi.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web.Http;

namespace Super.WebApi.Controllers
{
    [System.Web.Http.RoutePrefix("api/Students")]
    public class StudentsController : ApiController
    {
        Student[] students = new Student[]
         {
            new Student { Id = 1, Name = "TomatoSoup", Age = 18 },
            new Student { Id = 2, Name = "Yoyo", Age = 19 },
            new Student { Id = 3, Name = "Hammer", Age = 20 }
         };
        [Authorize]
        [Route("")]
        public IEnumerable<Student> GetAllStudents()
        {
            return students;
        }
        [Authorize]
        public Student GetStudentById(int id)
        {
            var student = students.FirstOrDefault((p) => p.Id == id);
            if (student == null)
            {
                throw new HttpResponseException(HttpStatusCode.NotFound);
            }
            return student;
        }
    }
}

完成以上三個步驟,可以直接不受權限控制訪問,這樣可能導致數據暴露不安全,所有我們引入了令牌認證的方式,防止非法的訪問;
4)、第四步安裝所需的NuGet包:
打開NuGet包管理器控制檯,然後輸入如下指令:
Install-Package Microsoft.AspNet.WebApi.Owin -Version 5.1.2 Install-Package Microsoft.Owin.Host.SystemWeb -Version 2.1.0 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
5)、第五步在更目錄下添加Startup類和SimpleAuthorizationServerProvider類

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;
using Super.WebApi;

[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(1),
                Provider = new SimpleAuthorizationServerProvider()
            };
            app.UseOAuthAuthorizationServer(OAuthServerOptions);
            app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
        }
    }
}

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);

        }
    }
}

6)、第六步修改StudentsController
在方法之前添加標記 [Authorize]

           [Authorize]
            public Student GetStudentById(int id)
            {
                var student = students.FirstOrDefault((p) => p.Id == id);
                if (student == null)
                {
                    throw new HttpResponseException(HttpStatusCode.NotFound);
                }
                return student;
            }

項目目錄如下:
在這裏插入圖片描述
完成以上步驟後,進行接口訪問
1)、直接訪問會請求失敗,顯示未授權
在這裏插入圖片描述
2)、先進行Post請求獲取驗證的token數據
返回:
{
“access_token”: “wS8l2AlXgK5fy6go9YwfwplYGIioU9Bznsi0YTddv9w7u1TwHloaoZEUQtFeSz2hOKC3h4beWEza69MKRM3es_86WKKeWh3faamcV7YTtuthaHR0l_Zk4U9DGNv0pE5Sgw4Rq_q0CJCz76b_IZysNiUJ3xpOM8D78UQAYGfwpeQlsQWHumu6YYTCStHuTes-2BuzavbAEC8pX3FWM0Km65GVe2mTZLvOUkpmHB3fKug”,
“token_type”: “bearer”,
“expires_in”: 86399
}
在這裏插入圖片描述
3)、在調用指定接口帶入驗證數據
“access_token”: “wS8l2AlXgK5fy6go9YwfwplYGIioU9Bznsi0YTddv9w7u1TwHloaoZEUQtFeSz2hOKC3h4beWEza69MKRM3es_86WKKeWh3faamcV7YTtuthaHR0l_Zk4U9DGNv0pE5Sgw4Rq_q0CJCz76b_IZysNiUJ3xpOM8D78UQAYGfwpeQlsQWHumu6YYTCStHuTes-2BuzavbAEC8pX3FWM0Km65GVe2mTZLvOUkpmHB3fKug”
在這裏插入圖片描述
參考:
1、https://www.cnblogs.com/relax/p/4956441.html
2、https://blog.csdn.net/qq285679784/article/details/80108389
項目源碼:
https://github.com/StevenLdh/Super.Sdk.git
以上內容個人學習認知與大家分享,還望大家一起相互學習,不足之處,歡迎留言指教~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章