您的位置:首页 > 其它

ADO.NET Data Service:如何做身份验证

2010-02-28 23:39 405 查看
ADO.NETDataService是基于WCF的一套REST风格的服务,但是它在很多方面又与WCF很不一样,典型的情况就是在身份验证方面。这篇文章专门来说一说如何为其实现身份验证。

1.采用Windows验证方式。

这种方式总是最简单也是最安全的。基本上我们也无需做太多事情。

web.config中配置

<authenticationmode="Windows"/>
<authorization>
<allowusers="Chenxizhang-pc\chenxizhang"/>
<denyusers="*"/>
</authorization>


.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;}

DataService里面,我们要通过所谓的QueryInterceptor进行拦截

[QueryInterceptor("Customers")]
publicExpression<Func<Customers,bool>>OnQueryCustomers()
{
if(!HttpContext.Current.User.Identity.IsAuthenticated)
thrownewAuthenticationException();
else
return(c)=>true;
}

.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;}

这样,我们就实现了目的:该服务(或者说其他的网站资源),只允许Chenxizhang-pc\chenxizhang这个账号能访问到。

接下来,客户端中应该怎么做呢?

localhost.NorthwindEntitiescontext=newlocalhost.NorthwindEntities(
newUri("http://localhost:2549/NorthwindService.svc/"));

context.Credentials=System.Net.CredentialCache.DefaultNetworkCredentials;
////查询
varquery=fromcincontext.Customers
wherec.City.Equals("London")
selectc;

Console.WriteLine(query.ToString());
foreach(variteminquery)
{
Console.WriteLine(item.CompanyName);
}
现在我的身份是合法的,所以能看到结果


但是如果我把下面这一句去除掉
<allowusers="Chenxizhang-pc\chenxizhang"/>


.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;}

就会发生一个错误





很好,我们这样就实现了身份验证了。
等一下,这样是否就真的万事大吉了呢?大家要知道,不是任何场合都有机会使用Windows验证的,例如在internet上,可能就无法使用Windows验证方式。
那么,是不是可以使用传统的Forms验证呢?如果在一个网站内部,那么看起来确实可以:先让用户去一个页面(Login.aspx)进行登录,此时它的凭据会保存起来,然后再访问服务的话就拥有了身份。
但是,问题是,如果仅仅在网站内部使用,那么有什么必要用DataService呢?为什么不直接用EDM去存取数据库呢?
好吧,那么,如果我们既希望在外部能访问到这个DataService,又不想用Windows验证,并且我们也无法使用Forms验证,那么该怎么办呢?答案是自定义验证。
首先,我们编写一个HttpModule
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
usingSystem.Web;
usingSystem.Security.Principal;

namespaceDataServiceAuthenticationModule
{
publicclassAuthenticationModule:IHttpModule
{
conststringaccessDeniedStatus="拒绝访问";
conststringaccessDeniedHtml="<html><body>401您的请求被拒绝,因为没有通过身份验证</body></html>";
conststringrealmFormatString="Basicrealm=\"{0}\"";
conststringauthServerHeader="WWW-Authenticate";
conststringauthClientHeader="Authorization";
conststringbasicAuth="Basic";

#regionIHttpModule成员

publicvoidDispose()
{

}

publicvoidInit(HttpApplicationcontext)
{
context.AuthenticateRequest+=newEventHandler(context_AuthenticateRequest);
}

voidcontext_AuthenticateRequest(objectsender,EventArgse)
{
HttpApplicationcontext=(HttpApplication)sender;
if(context.Request.Headers["Authorization"]==null)
{

context.Response.StatusCode=401;
context.Response.StatusDescription=accessDeniedStatus;
context.Response.Write(accessDeniedHtml);
//TODO:notsurethisisquiterightwrtrealm.

context.Response.AddHeader(authServerHeader,string.Format(realmFormatString,context.Request.Url.GetLeftPart(UriPartial.Authority)));

}

else
{

stringcredential=ASCIIEncoding.ASCII.GetString(Convert.FromBase64String(GetBase64CredentialsFromHeader()));

string[]usernameandpassword=credential.Split(':');
context.Context.User=newMyPrinciple(
newMyIdentity(usernameandpassword[0],Authenticate(usernameandpassword[0],usernameandpassword[1])));

}

}

boolAuthenticate(stringusername,stringpassword)
{
//yourcodelogicheretoauthenticateuser

if(username!="chenxizhang"||password!="password")returnfalse;
else
returntrue;

}

stringGetBase64CredentialsFromHeader()
{

stringcredsHeader=HttpContext.Current.Request.Headers[authClientHeader];

stringcreds=null;

intcredsPosition=

credsHeader.IndexOf(basicAuth,StringComparison.OrdinalIgnoreCase);

if(credsPosition!=-1)
{

credsPosition+=basicAuth.Length+1;

creds=credsHeader.Substring(credsPosition,

credsHeader.Length-credsPosition);

}

return(creds);

}

#endregion
}

publicclassMyPrinciple:IPrincipal
{

privateIIdentity_id;

publicMyPrinciple(IIdentityid)
{

_id=id;

}

publicIIdentityIdentity
{

get{return_id;}

}

publicboolIsInRole(stringrole)
{

thrownewNotImplementedException();

}

}

publicclassMyIdentity:IIdentity
{

privatebool_isAuthenticated=false;

privatestring_name;

publicMyIdentity(stringname,boolisAuthenticated)
{

_isAuthenticated=isAuthenticated;

_name=name;

}

publicstringAuthenticationType
{

get{thrownewNotImplementedException();}

}

publicboolIsAuthenticated
{

get{return_isAuthenticated;}

}

publicstringName
{

get{return_name;}

}

}

}


.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;}

然后,我们将web.config中的身份验证模式改为不验证(也就是说由我们自定义验证)

<authenticationmode="None"/>


.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;}

然后,我们将上面这个模块注册到配置文件中

<addname="DataServiceAuthentication"type="DataServiceAuthenticationModule.AuthenticationModule,DataServiceAuthenticationModule"/>


.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;}

配置好之后,我们再次运行一下客户端,收到了如下的错误。这一点都不奇怪,因为我们并没有传递身份过来。





那么客户端应该如何传递身份呢

context.Credentials=newSystem.Net.NetworkCredential("chenxizhang","password");


.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;}

这样的话,我们就能如愿看到结果了





写到这里,我想很多朋友就看明白了,我们做了一个自定义的HttpModule,接管了请求的身份验证过程。那么现在的做法是直接比较用户名和密码,是不是很不合理呢?
当然,正式的环境下我们不能这么做,但是你既然拿到了username,和password,其实你要怎么验证都不重要了。
.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;}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: