单点登录(SSO)的一点思考
这几天稍微关注了一下SOA方面的资料,抛开webservice性能问题不说,就当当这验证问题就让人头疼
考虑到几点:
1、调用方法的时候把用户名密码都带上,显然不太理想,每次都需要传递密码也不太那个安全,而且每次都要验证用户名和密码正确性,麻烦
2、不把用户名和密码带上,怎么知道这次来连接的是谁呢?
由上面2个问题,突然考虑到单点登录,我只登录一次,只把用户和密码传递一次不就行了嘛,听起来不错,可是问题又来了,你下次调用的时候
我怎么知道你已经登录并且有权限呢?于是考虑到 在第一次登录成功的时候返回给你一串加密的字符串,以后你每次来调用我方法的时候,带上
这个已经验证过的字符串不就可以了嘛,听起来还是不错,可是每次调用方法的时候都必须带上这串字符串岂不是还是很累赘?
暂时不考虑那么多了,就怎么先实现以下吧,希望高手们多多给建议。。。
稍微画了下图:
客户端首先需要调用Login方法,去验证服务器(SSO Server)验证,成功后携带ssokey返回,SsoServer保存登陆成功的用户。
客户端调用应用服务器方法时必须携带ssokey,以便应用服务器验证用户是否登陆。
关于 Application Server 和 SSO Server 如何通讯,我想有多种方式可以解决,比如说 Remoting/WebService/Wcf 等。。。。。
当然我们也可以把验证服务器和应用程序服务器放到一台服务器上。。。。
下面就可以通过具体代码来实现了:
为了方便,这里我采用webservice方式来通讯,我建立2个webserviice
1、SSOServer.asmx
2、MyApplicationService.asmx
这里 使我的应用也以 webservice的形式发布(SOA嘛。。)
1、SSOServer.asmx代码如下,其中只包括了 Login(登陆) 和 IsLogin(验证是否已经登录)方法
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Web;
5 using System.Web.Services;
6
7 namespace SSOTest
8 {
9 /// <summary>
10 /// SSOServer 的摘要说明
11 /// </summary>
12 [WebService(Namespace = "http://tempuri.org/")]
13 [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
14 [System.ComponentModel.ToolboxItem(false)]
15 // 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消对下行的注释。
16 [System.Web.Script.Services.ScriptService]
17 public class SSOServer : System.Web.Services.WebService
18 {
19 //key:用户名 value:ssokey
20 public static Dictionary<string, string> onlineUser = new Dictionary<string, string>();
21
22 [WebMethod]
23 public string Login(string userName, string passWord)
24 {
25 //验证用户名密码
26 if ("huwei".Equals(userName))
27 {
28 //
29 if (onlineUser.ContainsKey(userName))
30 {
31 onlineUser.Remove(userName);
32 }
33
34 //成功后生成新的ssokey并返回
35 string ssokey = Guid.NewGuid().ToString();
36
37 onlineUser.Add(userName,ssokey);
38 return ssokey;
39 }
40 return "";
41 }
42
43 //判断是否已经登录
44 [WebMethod]
45 public bool IsLogin(string ssokey)
46 {
47 return onlineUser.ContainsValue(ssokey);
48 }
49 }
50 }
51
这里只是简单的测试一下,实际上还有很多需要考虑的因素,比如说 你的 ssokey 保存的时间,总不至于ssokey一直保存着吧
2、MyApplicationService.asmx
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Web;
5 using System.Web.Services;
6 using System.Web.Script.Services;
7
8 namespace SSOTest
9 {
10 /// <summary>
11 /// MyApplicationService 的摘要说明
12 /// </summary>
13 [WebService(Namespace = "http://tempuri.org/")]
14 [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
15 [System.ComponentModel.ToolboxItem(false)]
16 // 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消对下行的注释。
17 [System.Web.Script.Services.ScriptService]
18 public class MyApplicationService : System.Web.Services.WebService
19 {
20 [WebMethod]
21 [ScriptMethod(ResponseFormat=ResponseFormat.Json,UseHttpGet=true)]
22 public string TestMethod(string ssokey)
23 {
24 SSOServer server = new SSOServer();
25 if (server.IsLogin(ssokey))
26 {
27 Console.WriteLine("恭喜!认证成功!");
28
29 try
30 {
31 MySqlHelper helper = new MySqlHelper();
32 helper.Execute("insert into Friends (firstname,lastname,age,email) values ('fff','lll',22,'aaeeee')");
33 }
34 catch (Exception e)
35 {
36 Console.WriteLine(e.Message);
37 }
38
39 return "恭喜!认证成功!";
40 }
41 else
42 {
43 Console.WriteLine("抱歉!认证失败!请重新登录");
44 return "抱歉!认证失败!请重新登录";
45 }
46 }
47 }
48 }
49
3、前台测试一下,采用jquery ajax 来登录,并执行方法
在 Default.aspx 页面中加入如下脚本
1 <script type="text/javascript" src="Scripts/jquery-1.4.1.min.js"></script>
2 <script type="text/javascript">
3 var ssokey = "";
4
5 function doLogin(userName, passWord) {
6 $.ajax({
7 url: "http://localhost:11143/SSOServer.asmx/Login",
8 type: "post",
9 data: "username=" + userName + "&passWord=" + passWord,
10 success: function (data) {
11 //alert($(data).find("string").text());
12 ssokey = $(data).find("string").text();
13 alert("登录成功");
14 }
15 });
16 }
17
18 function doJSON() {
19 $.ajax({
20 url: "http://localhost:11143/MyApplicationService.asmx/TestMethod",
21 data: {ssokey:"'" + ssokey + "'"},
22 dataType: "JSON",
23 contentType: "application/json; charset=utf-8",
24 success: function (data) {
25 alert(data);
26 }
27 });
28 }
29 </script>
这里写了 2个方法,一个是登陆方法,首先必须要先登陆获得 ssokey,然后才能成功的执行 方法
总结:
这种方式我觉得还是不太好,毕竟每次执行方法都要检测ssokey是否已经登录,肯定存在浪费的情况,不知道各位高手有没有更好的解决方案。