您的位置:首页 > 编程语言 > ASP

[翻译]创建ASP.NET WebApi RESTful 服务(8)

2014-04-13 18:09 489 查看
本章讨论创建安全的WebApi服务,到目前为止,我们实现的API都是基于未加密的HTTP协议,大家都知道在Web中传递身份信息必须通过HTTPS,接下来我们来实现这一过程。

使用HTTPS

其实可以通过IIS配置,将整个WebApi的访问都配置为Https,但实际上,如果希望只是对部分方法进行认证,那就必须通过认证身份信息进行处理。

下面介绍通过Filter来实现这一过程,如果身份认证不通过,就返回一条信息,提示访问者通过https进行访问。

publicclassForceHttpsAttribute:AuthorizationFilterAttribute
{
publicoverridevoidOnAuthorization(System.Web.Http.Controllers.HttpActionContextactionContext)
{
varrequest=actionContext.Request;
if(request.RequestUri.Scheme!=Uri.UriSchemeHttps)
{
varhtml="<p>Httpsisrequired</p>";
if(request.Method.Method=="GET")
{
actionContext.Response=request.CreateResponse(HttpStatusCode.Found);
actionContext.Response.Content=newStringContent(html,Encoding.UTF8,"text/html");
UriBuilderhttpsNewUri=newUriBuilder(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=newStringContent(html,Encoding.UTF8,"text/html");
}
}
}
}

.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}

通过actionContext参数获取Request和Response对象,对URI进行检查,如果不是以HTTPS开头,就返回443代码。

使用的方法有两种,一种是在WebAPIConfig中注册为全局的Attribute。

publicstaticvoidRegister(HttpConfigurationconfig)
{
config.Filters.Add(newForceHttpsAttribute());
}

.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}

另一种是对制定的类或者方法进行拦截。

//EnforceHTTPSontheentirecontroller
[Learning.Web.Filters.ForceHttps()]
publicclassCoursesController:BaseApiController
{
//EnforceHTTPSonPOSTmethodonly
[Learning.Web.Filters.ForceHttps()]
publicHttpResponseMessagePost([FromBody]CourseModelcourseModel)
{
}
}

.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}

通过BasicAuthentication进行认证

当前所有的API都是Public的,网络上的任意用户都可以请求资源。实际的项目中肯定要对访问者进行必要的限制。

假设对于客户端的请求“http://{your_port}/api/students/{userName}”,当有正确的身份信息时,我们返回username为“TaiseerJoudeh”的信息,否则,返回错误;
如果请求是POST类型,如“http://{your_port}/api/courses/2/students/{userName}”,那么修改者也必须通过身份认证才可以进行修改。

什么是BasicAuthentication

BasicAuthentication提供了一种在HttpRequest被处理之前先行进行身份认证的模式,它在防止Dos等方面具有重要作用。BasicAuthentication要求在请求时必须在HttpHeader提供基于Base64编码的用户名和密码信息。这种认证一般应该通过HTTPS来实现。

publicclassLearningAuthorizeAttribute:AuthorizationFilterAttribute
{
[Inject]
publicLearningRepositoryTheRepository{get;set;}
publicoverridevoidOnAuthorization(System.Web.Http.Controllers.HttpActionContextactionContext)
{
//Casethatuserisauthenticatedusingformsauthentication
//sononeedtocheckheaderforbasicauthentication.
if(Thread.CurrentPrincipal.Identity.IsAuthenticated)
{
return;
}
varauthHeader=actionContext.Request.Headers.Authorization;
if(authHeader!=null)
{
if(authHeader.Scheme.Equals("basic",StringComparison.OrdinalIgnoreCase)&&
!String.IsNullOrWhiteSpace(authHeader.Parameter))
{
varcredArray=GetCredentials(authHeader);
varuserName=credArray[0];
varpassword=credArray[1];
if(IsResourceOwner(userName,actionContext))
{
//YoucanuseWebsecurityorasp.netmemebrshipprovidertologin,for
//forhesakeofkeepingexamplesimple,weusedoutownloginfunctionality
if(TheRepository.LoginStudent(userName,password))
{
varcurrentPrincipal=newGenericPrincipal(newGenericIdentity(userName),null);
Thread.CurrentPrincipal=currentPrincipal;
return;
}
}
}
}
HandleUnauthorizedRequest(actionContext);
}
privatestring[]GetCredentials(System.Net.Http.Headers.AuthenticationHeaderValueauthHeader)
{
//Base64encodedstring
varrawCred=authHeader.Parameter;
varencoding=Encoding.GetEncoding("iso-8859-1");
varcred=encoding.GetString(Convert.FromBase64String(rawCred));
varcredArray=cred.Split(':');
returncredArray;
}
privateboolIsResourceOwner(stringuserName,System.Web.Http.Controllers.HttpActionContextactionContext)
{
varrouteData=actionContext.Request.GetRouteData();
varresourceUserName=routeData.Values["userName"]asstring;
if(resourceUserName==userName)
{
returntrue;
}
returnfalse;
}
privatevoidHandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContextactionContext)
{
actionContext.Response=actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
actionContext.Response.Headers.Add("WWW-Authenticate",
"BasicScheme='eLearning'location='http://localhost:8323/account/login'");
}
}

.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}

上述代码实现了以下逻辑:

从RequestHeader中获取认证信息;
确认Header的Schema被设置为basic,并包含了正确的Base64编码字符串;
将字符串转换为“username:password”格式,获取各自内容;
验证身份信息,确定是否具有相应权限;
如果Credentials验证无误,设置当前线程的Identity信息,以便子请求能够重用;
如果验证有无,则返回401错误。

现在可以对指定的方法进行标记。

publicclassStudentsController:BaseApiController
{
[LearningAuthorizeAttribute]
publicHttpResponseMessageGet(stringuserName)
{
}
}
publicclassEnrollmentsController:BaseApiController
{
[LearningAuthorizeAttribute]
publicHttpResponseMessagePost(intcourseId,[FromUri]stringuserName,[FromBody]Enrollmentenrollment)
{
}
}
现在分别用FireFox和Fiddler进行测试。假设路径如下:http://localhost:{your_port}/api/students/TaiseerJoudeh。[/code]

FireFox:返回401,因为没有身份信息,一个弹出框会弹出,要求输入用户名和密码。输入正确的用户名和密码,就可以看到返回的json信息。而接下来的子请求,则无需再进行认证;

Fiddler:需要先拼接一个Base64加密“username:password”字符串,可以通过这里实现。注意:这不能算是加密,真正的加密必须通过HTTPS实现。当用户名密码正确时,会返回200和正确的json信息。

.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}

来源:http://bitoftech.net/2013/12/03/enforce-https-asp-net-web-api-basic-authentication/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: