国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

使用ASP.NET Web Api構(gòu)建基于REST風(fēng)格的服務(wù)實(shí)戰(zhàn)系列教程【八】——Web Api的安全性

2019-11-15 02:30:41
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

使用asp.net Web Api構(gòu)建基于REST風(fēng)格的服務(wù)實(shí)戰(zhàn)系列教程【八】——Web Api的安全性

系列導(dǎo)航地址http://www.survivalescaperooms.com/fzrain/p/3490137.html

前言

這一篇文章我們主要來(lái)探討一下Web Api的安全性,到目前為止所有的請(qǐng)求都是走的Http協(xié)議(http://),因此客戶(hù)端與服務(wù)器之間的通信是沒(méi)有加密的。在本篇中,我們將在“StudentController”中添加身份驗(yàn)證功能——通過(guò)驗(yàn)證用戶(hù)名與密碼來(lái)判斷是否是合法用戶(hù)。眾所周知,對(duì)于機(jī)密信息的傳遞,我們應(yīng)該使用安全的Http協(xié)議(https://)來(lái)傳輸

在Web Api中強(qiáng)制使用Https

我們可以在IIS級(jí)別配置整個(gè)Web Api來(lái)強(qiáng)制使用Https,但是在某些情況下你可能只需要對(duì)某一個(gè)action強(qiáng)制使用Https,而其他的方法仍使用http。

為了實(shí)現(xiàn)這一點(diǎn),我們將使用Web Api中的filters——filter(過(guò)濾器)的主要作用就是可以在我們執(zhí)行方法之前執(zhí)行一段代碼。沒(méi)接觸過(guò)得可以通過(guò)下圖簡(jiǎn)單理解下,大神跳過(guò):

無(wú)標(biāo)題

我們新創(chuàng)建的filter將用來(lái)檢測(cè)是否是安全的,如果不是安全的,filter將終止請(qǐng)求并返回相應(yīng):請(qǐng)求必須是https。

具體做法:創(chuàng)建一個(gè)filter繼承自AuthorizationFilterAttribute,重寫(xiě)OnAuthorization來(lái)實(shí)現(xiàn)我們的需求。

在網(wǎng)站根目錄下創(chuàng)建“Filters”文件夾,新建一個(gè)類(lèi)“ForceHttpsAttribute”繼承自“System.Web.Http.Filters.AuthorizationFilterAttribute”,下面上代碼:

public class ForceHttpsAttribute : AuthorizationFilterAttribute    {        public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)        {            var request = actionContext.Request;             if (request.RequestUri.Scheme != Uri.UriSchemeHttps)            {                var html = "<p>Https is required</p>";                 if (request.Method.Method == "GET")                {                    actionContext.Response = request.CreateResponse(HttpStatusCode.Found);                    actionContext.Response.Content = new StringContent(html, Encoding.UTF8, "text/html");                     UriBuilder httpsNewUri = new UriBuilder(request.RequestUri);                    httpsNewUri.Scheme = Uri.UriSchemeHttps;                    httpsNewUri.Port = 443;                     actionContext.Response.Headers.Location = httpsNewUri.Uri;                }                else                {                    actionContext.Response = request.CreateResponse(HttpStatusCode.NotFound);                    actionContext.Response.Content = new StringContent(html, Encoding.UTF8, "text/html");                }             }        }    }

在上面代碼中,我們通過(guò)actionContext參數(shù)拿到request和response對(duì)象,我們判斷客戶(hù)端的請(qǐng)求:如果不是https,那么直接響應(yīng)客戶(hù)端應(yīng)該使用https。

在這里,我們需要區(qū)分請(qǐng)求是Get還是其他(Post,Delete,Put),因?yàn)閷?duì)于使用了Http的Get請(qǐng)求來(lái)訪(fǎng)問(wèn)資源,我們將使用https創(chuàng)建一個(gè)連接并添加在響應(yīng)Header的Location中。這樣做了之后客戶(hù)端就會(huì)自動(dòng)使用https來(lái)發(fā)送Get請(qǐng)求了。

對(duì)于非Get請(qǐng)求,直接返回404,并通知客戶(hù)端必須使用https來(lái)請(qǐng)求

如果我們打算在整個(gè)項(xiàng)目中使用,那么在“WebAPIConfig”類(lèi)中做如下設(shè)置:

public static void Register(HttpConfiguration config)   {       config.Filters.Add(new ForceHttpsAttribute());   }

如果我們相對(duì)具體的Controller或Action設(shè)置時(shí),可以做如下設(shè)置:

//對(duì)于整個(gè)Controller強(qiáng)制使用Https
[Learning.Web.Filters.ForceHttps()]    public class CoursesController : BaseApiController    {    //僅對(duì)這個(gè)方法強(qiáng)制使用Https
        [Learning.Web.Filters.ForceHttps()]            public HttPResponseMessage Post([FromBody] CourseModel courseModel)            {         }}

使用Basic Authentication驗(yàn)證用戶(hù)

到目前為止,我們提供的所有Api都是公開(kāi)的,任何人都能訪(fǎng)問(wèn)。但在真是場(chǎng)景中卻是不可取的,對(duì)于某些數(shù)據(jù),只有通過(guò)認(rèn)證的用戶(hù)才能訪(fǎng)問(wèn),我們這里有兩個(gè)地方恰好說(shuō)明這一點(diǎn):

1.當(dāng)客戶(hù)端發(fā)送Get請(qǐng)求道“http://{your_port}/api/students/{userName}“的時(shí)候.例如:通過(guò)上述URI訪(fǎng)問(wèn)userNme為“TaiseerJoudeh”的信息時(shí),我們必須讓客戶(hù)端提供TaiseerJoudeh相應(yīng)的用戶(hù)名和密碼,對(duì)于沒(méi)有提供驗(yàn)證信息的用戶(hù)我們就不讓訪(fǎng)問(wèn),因?yàn)閷W(xué)生信息包含一些重要的私人信息(email,birthday等)。

2.當(dāng)客戶(hù)端發(fā)送Post請(qǐng)求到“http://{your_port}/api/courses/2/students/{userName}“的時(shí)候,這意味著給學(xué)生選課,我們可以想一下,這里如果不做驗(yàn)證,那么所有人都能隨便給某個(gè)學(xué)生選課,那么不就亂了么。

對(duì)于上面的場(chǎng)景,我們使用Basic Authentication來(lái)進(jìn)行身份驗(yàn)證,主要思路是使用filter從請(qǐng)求header部分獲取身份信息,校驗(yàn)驗(yàn)證類(lèi)型是否為“basic”,然后校驗(yàn)內(nèi)容,正確就放行,否則返回401 (Unauthorized)狀態(tài)碼。

在上代碼前,解釋一下下basic authentication:

什么是basic authentication?

它意味著在正式處理Http請(qǐng)求之前對(duì)請(qǐng)求者身份的校驗(yàn),這可以防止服務(wù)器受到DoS攻擊(Denial of service attacks)。原理是:客戶(hù)端在發(fā)送Http請(qǐng)求的時(shí)候在Header部分提供一個(gè)基于Base64編碼的用戶(hù)名和密碼,形式為“username:passWord”,消息接收者(服務(wù)器)進(jìn)行驗(yàn)證,通過(guò)后繼續(xù)處理請(qǐng)求。

由于用戶(hù)名和密碼僅適用base64編碼,因此為了保證安全性,basic authentication通常是基于SSL連接(https)

為了在我們的api中使用,創(chuàng)建一個(gè)類(lèi)“LearningAuthorizeAttribute”繼承自System.Web.Http.Filters.AuthorizationFilterAttribute

public class LearningAuthorizeAttribute : AuthorizationFilterAttribute    {         [Inject]        public LearningRepository TheRepository { get; set; }         public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)        {            //forms authentication Case that user is authenticated using forms authentication
//so no need to check header for basic authentication.            if (Thread.CurrentPrincipal.Identity.IsAuthenticated)            {                return;            }             var authHeader = actionContext.Request.Headers.Authorization;             if (authHeader != null)            {                if (authHeader.Scheme.Equals("basic", StringComparison.OrdinalIgnoreCase) &&                    !String.IsNullOrWhiteSpace(authHeader.Parameter))                {                    var credArray = GetCredentials(authHeader);                    var userName = credArray[0];                    var password = credArray[1];                     if (IsResourceOwner(userName, actionContext))                    {                        //You can use Websecurity or asp.net memebrship provider to login, for                        //for he sake of keeping example simple, we used out own login functionality                        if (TheRepository.LoginStudent(userName, password))                        {                            var currentPrincipal = new GenericPrincipal(new GenericIdentity(userName), null);                            Thread.CurrentPrincipal = currentPrincipal;                            return;                        }                    }                }            }             HandleUnauthorizedRequest(actionContext);        }         private string[] GetCredentials(System.Net.Http.Headers.AuthenticationHeaderValue authHeader)        {             //Base 64 encoded string            var rawCred = authHeader.Parameter;            var encoding = Encoding.GetEncoding("iso-8859-1");            var cred = encoding.GetString(Convert.FromBase64String(rawCred));             var credArray = cred.Split(':');             return credArray;        }         private bool IsResourceOwner(string userName, System.Web.Http.Controllers.HttpActionContext actionContext)        {            var routeData = actionContext.Request.GetRouteData();            var resourceUserName = routeData.Values["userName"] as string;             if (resourceUserName == userName)            {                return true;            }            return false;        }         private void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext)        {            actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);             actionContext.Response.Headers.Add("WWW-Authenticate",                                               "Basic Scheme='eLearning' location='http://localhost:8323/account/login'");         }    }

我們重寫(xiě)了“OnAuthorization”,實(shí)現(xiàn)如下功能:

1.從請(qǐng)求Header中獲取校驗(yàn)數(shù)據(jù)

2.判斷驗(yàn)證信息類(lèi)型為“basic”并包含base64編碼

3.將base64編碼轉(zhuǎn)化為string,并提取用戶(hù)名和密碼

4.校驗(yàn)提供的驗(yàn)證信息是否與訪(fǎng)問(wèn)的資源信息相同(學(xué)生的詳細(xì)信息只能由他自己訪(fǎng)問(wèn))

5.去數(shù)據(jù)庫(kù)校驗(yàn)用戶(hù)名及密碼

6.如果校驗(yàn)通過(guò),則設(shè)置Thread的CurrentPrincipal,使本次接下來(lái)的請(qǐng)求都是通過(guò)校驗(yàn)的。

7.校驗(yàn)沒(méi)通過(guò),返回401(Unauthorized)并添加一個(gè)WWW-Authenticate響應(yīng)頭,根據(jù)這個(gè)請(qǐng)求,客戶(hù)端可以添加相應(yīng)的驗(yàn)證信息

在代碼中實(shí)現(xiàn)起來(lái)就很簡(jiǎn)單了,上兩個(gè)Attribute就完了:

public class StudentsController : BaseApiController    {        [LearningAuthorizeAttribute]        public HttpResponseMessage Get(string userName)            {             }    }
public class EnrollmentsController : BaseApiController    {        [LearningAuthorizeAttribute]        public HttpResponseMessage Post(int courseId, [FromUri]string userName, [FromBody]Enrollment enrollment)            {             }    }

測(cè)試成果

使用測(cè)試工具發(fā)送如下請(qǐng)求:

發(fā)表評(píng)論 共有條評(píng)論
用戶(hù)名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 图木舒克市| 舒城县| 郓城县| 蒲江县| 满洲里市| 祁门县| 洛宁县| 江山市| 千阳县| 普定县| 九寨沟县| 湖南省| 二连浩特市| 板桥市| 横峰县| 汉沽区| 元氏县| 宜都市| 永兴县| 海丰县| 年辖:市辖区| 卢氏县| 嫩江县| 大兴区| 北碚区| 磐安县| 深水埗区| 封开县| 宿州市| 广汉市| 正阳县| 山西省| 蓬安县| 哈密市| 阿城市| 伊吾县| 桓仁| 离岛区| 保山市| 兴业县| 象山县|