【IT168技术】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版的.很快我们就可以找出他的关键代码:
Action为:
02 public ActionResult Authenticate(string returnUrl) {
03 var response = openid.GetResponse();
04 if (response == null) {
05 // Stage 2: user submitting Identifier
06 Identifier id;
07 if (Identifier.TryParse(Request.Form["openid_identifier"], out id)) {
08 try {
09 return openid.CreateRequest(Request.Form["openid_identifier"]).RedirectingResponse.AsActionResult();
10 } catch (ProtocolException ex) {
11 ViewData["Message"] = ex.Message;
12 return View("Login");
13 }
14 } else {
15 ViewData["Message"] = "Invalid identifier";
16 return View("Login");
17 }
18 } else {
19 // Stage 3: OpenID Provider sending assertion response
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);
26 } else {
27 return RedirectToAction("Index", "Home");
28 }
29 case AuthenticationStatus.Canceled:
30 ViewData["Message"] = "Canceled at provider";
31 return View("Login");
32 case AuthenticationStatus.Failed:
33 ViewData["Message"] = response.Exception.Message;
34 return View("Login");
35 }
36 }
37 return new EmptyResult();
38 }
39 }
最后在HomeController 的Index Action(就是主页)增加 X-XRDS-Location 的Header. Xrds Action是输出上面的Xrds View.如下: 其中请注意xrds的地址. 代码如下.
02 public ActionResult Index() {
03 Response.AppendHeader(
04 "X-XRDS-Location",
05 new Uri(Request.Url, Response.ApplyAppPathModifier("~/Home/xrds")).AbsoluteUri);
06 return View("Index");
07 }
08
09 public ActionResult Xrds() {
10 return View("Xrds");
11 }
12 }
XRDS 的View为:
view sourceprint?01
02
09
10 xmlns:xrds="xri://$xrds"
11 xmlns:openid="http://openid.net/xmlns/1.0"
12 xmlns="xri://$xrd*($v*2.0)">
13
14
15 http://specs.openid.net/auth/2.0/return_to
这样就OK啰. 这只是简单的用法. 因为这个只返回很少信息. 一般只有两个,一个是:FriendlyIdentifierForDisplay ,就是用户名,一个是ClaimedIdentifier, 是用户的标识. 如果是这样用就OK,那我这文章也写得没什么意义了.呵. 因为一般我们还要抓到用户的Email,和个性图标.等等一些有用的东西.但是默认的是不返回的.
先看看可以返回什么信息. DotNetOpenAuth中有一个WellKnownAttributes 类, 这个类中定义了一系列可以返回的信息. 下面是这个类的抓图:
如何获取这些信息呢? 请看下面的示例代码 :
02 public ActionResult Login(string openid_identifier)
03 {
04 try
05 {
06 var openid = new OpenIdRelyingParty();
07 IAuthenticationRequest request = openid.CreateRequest(Identifier.Parse(openid_identifier));
08 var fetch = new FetchRequest();
09 fetch.Attributes.AddRequired(WellKnownAttributes.Contact.Email);
10 fetch.Attributes.AddRequired(WellKnownAttributes.Name.Alias);
11 fetch.Attributes.AddRequired(WellKnownAttributes.Name.FullName);
12 fetch.Attributes.AddRequired(WellKnownAttributes.Media.Images.Default);
13 request.AddExtension(fetch);
14
15 /*
16 request.AddExtension(new ClaimsRequest
17 {
18 Email = DemandLevel.Require,
19 FullName = DemandLevel.Require,
20 Nickname = DemandLevel.Require
21 });*/
22 return request.RedirectingResponse.AsActionResult();
23 }
24 catch
25 {
26 ViewData["ErrorMessage"] = "您输入的OpenID不正确或您的帐号的提供商不提供OpenID服务";
27
28 ViewData["OpenIDLoginURL"] = openid_identifier;
29 return View();
30 }
31 }
这样创建请求就可以成功获取你想要的信息了, 这里是请求获取 Email, 姓名, 个性图标.
注意我注释了的代码, 一开始我也用这样,但是,这个无法获取个性图标.
最后,最后很关键喔.. 配置文件!! 对.. 一开始我因为没注意这个,花了不少时间.. ======
http://www.86e0.com 用的配置文件如下,基本是抄OpenIdRelyingPartyMvc 这个示例的.
好了,现在基本没问题了.
剩下就是在登录成功后获取这些信息了. 相关的代码如下:
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;
07
08 if (nickName.Length > 50) { nickName = nickName.Substring(0, 50); }
09
10 var claim = response.GetExtension();
11 var fetch = response.GetExtension();
12
13 string picKey = WellKnownAttributes.Media.Images.Default;
14
15 if (fetch !=null && fetch.Attributes != null && fetch.Attributes.Contains(picKey))
16 {
17 var picAttr = fetch.Attributes[picKey];
18 if (picAttr != null && picAttr.Values.Count > 0) { picIcon = picAttr.Values[0]; }
19 }
20 if (claim != null)
21 {
22 nickName = claim.Nickname;
23
24 if (string.IsNullOrEmpty(nickName))
25 {
26 int ttIndex = claim.Email.IndexOf("@");
27 if (ttIndex > 0)
28 {
29 nickName = claim.Email.Substring(0, ttIndex);
30 }
31 else
32 {
33 nickName = claim.Email;
34 }
35 }
36 email = claim.Email;
37 }
38 // 最后授权,入库等.
39 case AuthenticationStatus.Canceled:
40 ViewData["Message"] = "Canceled at provider";
41 return View("Login");
42 case AuthenticationStatus.Failed:
43 ViewData["Message"] = response.Exception.Message;
44 return View("Login");
45 }
OK了. 上面的这么多 if是因为抓出来的资料会有 null的情况.. 这个应该是用户没设定那些资料.