[转载]为您的.NET网站增加OpenID,Window Live,人人网等多种登录方式之一: 增加OpenID登录 – Otis’s Technology Space – 博客园.
OpenID在国外很流行. 在国内就不怎么样了.. 很多网站,论坛都不支持. 经常在网上逛的人,几乎都要注册很多帐号,记很多密码. 或者是帐号和密码都设定一样.呵. 我在想,如果国内大量的论坛都支持OpenID登录,那么,将会多爽!
不了解OpenID的朋友可 以看中文,或英文http://www.openid.net 的介绍.
本人最近 做的一个网站( http://www.86e0.com ) 有用到OpenID的登录(当然还有其它的登录方式,慢慢会说到). 一开始我也是狂找资料, 中文的,英文的都找过了.可惜的是,资料少得很. 下面总结一些经验和分享一些代码.
.NET下使用OpenID,首先要去下载一个第三方组件:dotnetopenauth. 网址为: http://www.dotnetopenauth.net/
压缩包里会有示例. 由于我的项目是用ASP.NET MVC2,所以我直接看OpenIdRelyingPartyMvc 这个示例. 示例是ASP.NET MVC1.0版的.很快我们就可以找出他的关键代码:
HTML为:
1 |
< form action = "Authenticate?ReturnUrl=<%=HttpUtility.UrlEncode(Request.QueryString[" ReturnUrl"]) %>" method="post"> |
2 |
< label for = "openid_identifier" >OpenID: </ label > |
3 |
< input id = "openid_identifier" name = "openid_identifier" size = "40" /> |
4 |
< input type = "submit" value = "Login" /> |
Action为:
01 |
[ValidateInput( false )] |
02 |
public ActionResult Authenticate( string returnUrl) { |
03 |
var response = openid.GetResponse(); |
04 |
if (response == null ) { |
07 |
if (Identifier.TryParse(Request.Form[ "openid_identifier" ], out id)) { |
09 |
return openid.CreateRequest(Request.Form[ "openid_identifier" ]).RedirectingResponse.AsActionResult(); |
10 |
} catch (ProtocolException ex) { |
11 |
ViewData[ "Message" ] = ex.Message; |
15 |
ViewData[ "Message" ] = "Invalid identifier" ; |
20 |
switch (response.Status) { |
21 |
case AuthenticationStatus.Authenticated: |
22 |
Session[ "FriendlyIdentifier" ] = response.FriendlyIdentifierForDisplay; |
23 |
FormsAuthentication.SetAuthCookie(response.ClaimedIdentifier, false ); |
24 |
if (! string .IsNullOrEmpty(returnUrl)) { |
25 |
return Redirect(returnUrl); |
27 |
return RedirectToAction( "Index" , "Home" ); |
29 |
case AuthenticationStatus.Canceled: |
30 |
ViewData[ "Message" ] = "Canceled at provider" ; |
32 |
case AuthenticationStatus.Failed: |
33 |
ViewData[ "Message" ] = response.Exception.Message; |
37 |
return new EmptyResult(); |
最后在HomeController 的Index Action(就是主页)增加 X-XRDS-Location 的Header. Xrds Action是输出上面的Xrds View.如下: 其中请注意xrds的地址. 代码如下.
01 |
public class HomeController : Controller { |
02 |
public ActionResult Index() { |
03 |
Response.AppendHeader( |
05 |
new Uri(Request.Url, Response.ApplyAppPathModifier( "~/Home/xrds" )).AbsoluteUri); |
09 |
public ActionResult Xrds() { |
XRDS 的View为:
01 |
<%@ Page Language= "C#" Inherits= "System.Web.Mvc.ViewPage" ContentType= "application/xrds+xml" %><?xml version= "1.0" encoding= "UTF-8" ?> |
03 |
This page is a required for relying party discovery per OpenID 2.0. |
04 |
It allows Providers to call back to the relying party site to confirm the |
05 |
identity that it is claiming in the realm and return_to URLs. |
06 |
This page should be pointed to by the 'realm' home page, which in this sample |
12 |
xmlns= "xri://$xrd*($v*2.0)" > |
14 |
<Service priority= "1" > |
16 |
<%-- Every page with an OpenID login should be listed here. --%> |
17 |
<%-- We use the Authenticate action instead of Login because Authenticate |
18 |
is the action that receives OpenId assertions. --%> |
19 |
<URI><%= new Uri(Request.Url, Response.ApplyAppPathModifier( "~/user/authenticate" ))%></URI> |
这样就OK啰. 这只是简单的用法. 因为这个只返回很少信息. 一般只有两个,一个是:FriendlyIdentifierForDisplay ,就是用户名,一个是ClaimedIdentifier, 是用户的标识. 如果是这样用就OK,那我这文章也写得没什么意义了.呵. 因为一般我们还要抓到用户的Email,和个性图标.等等一些有用的东西.但是默认的是不返回的.
先看看可以返回什么信息. DotNetOpenAuth中有一个WellKnownAttributes 类, 这个类中定义了一系列可以返回的信息. 下面是这个类的抓图:
如何获取这些信息呢? 请看下面的示例代码 :
01 |
[AcceptVerbs(HttpVerbs.Post)] |
02 |
public ActionResult Login( string openid_identifier) |
06 |
var openid = new OpenIdRelyingParty(); |
07 |
IAuthenticationRequest request = openid.CreateRequest(Identifier.Parse(openid_identifier)); |
10 |
var fetch = new FetchRequest(); |
11 |
fetch.Attributes.AddRequired(WellKnownAttributes.Contact.Email); |
12 |
fetch.Attributes.AddRequired(WellKnownAttributes.Name.Alias); |
13 |
fetch.Attributes.AddRequired(WellKnownAttributes.Name.FullName); |
14 |
fetch.Attributes.AddRequired(WellKnownAttributes.Media.Images.Default); |
15 |
request.AddExtension(fetch); |
25 |
return request.RedirectingResponse.AsActionResult(); |
29 |
ViewData[ "ErrorMessage" ] = "您输入的OpenID 不正确或您的帐号的提供商不提供OpenID服务" ; |
31 |
ViewData[ "OpenIDLoginURL" ] = openid_identifier; |
这样创建请求就可以成功获取你想要的信息了, 这里是请求获取 Email, 姓名, 个性图标.
注意我注释了的代码, 一开始我也用这样,但是,这个无法获取个性图标.
最后,最后很关键喔.. 配置文件!! 对.. 一开始我因为没注意这个,花了不少时间.. ======
http://www.86e0.com 用的配置文件如下,基本是抄OpenIdRelyingPartyMvc 这个示例的.
04 |
< security requireSsl = "false" /> |
08 |
< add type = "DotNetOpenAuth.OpenId.Behaviors.AXFetchAsSregTransform, DotNetOpenAuth" /> |
16 |
< add name = "localhost" /> |
18 |
</ untrustedWebRequest > |
21 |
< reporting enabled = "false" /> |
好了,现在基本没问题了.
剩下就是在登录成功后获取这些信息了. 相关的代码如下:
01 |
switch (response.Status) { |
02 |
case AuthenticationStatus.Authenticated: |
03 |
string nickName = response.FriendlyIdentifierForDisplay; |
04 |
if ( string .IsNullOrEmpty(nickName)) nickName = "匿名用户" ; |
05 |
string email = string .Empty; |
06 |
string picIcon = string .Empty; |
08 |
if (nickName.Length > 50) { nickName = nickName.Substring(0, 50); } |
10 |
var claim = response.GetExtension<ClaimsResponse>(); |
11 |
var fetch = response.GetExtension<FetchResponse>(); |
13 |
string picKey = WellKnownAttributes.Media.Images.Default; |
15 |
if (fetch != null && fetch.Attributes != null && fetch.Attributes.Contains(picKey)) |
17 |
var picAttr = fetch.Attributes[picKey]; |
18 |
if (picAttr != null && picAttr.Values.Count > 0) { picIcon = picAttr.Values[0]; } |
22 |
nickName = claim.Nickname; |
24 |
if ( string .IsNullOrEmpty(nickName)) |
26 |
int ttIndex = claim.Email.IndexOf( "@" ); |
29 |
nickName = claim.Email.Substring(0, ttIndex); |
33 |
nickName = claim.Email; |
39 |
case AuthenticationStatus.Canceled: |
40 |
ViewData[ "Message" ] = "Canceled at provider" ; |
42 |
case AuthenticationStatus.Failed: |
43 |
ViewData[ "Message" ] = response.Exception.Message; |
OK了. 上面的这么多 if是因为抓出来的资料会有 null的情况.. 这个应该是用户没设定那些资料.
最后,个人博客的话, 不用这么麻烦,比如说老赵的个人博客,直接用https://rpxnow.com/的服务就好了.呵.
感兴趣的朋友欢迎去http://www.86e0.com 体验.
这个系列应该会写三四个. 第二个应该是加入Window live 的登录. 因为Live官方的OpenID登录还在开发中.. 所以不得不用 live sdk 的方式去做.