异构单点登录

 异构系统间的单点登录,实际上是“伪单点”,极其简单的原理可用于参考。vb to java


开源项目地址:

https://github.com/felixyin/SingleLoginForWeb/

 
一、开发原因:
    0、项目中需要url加密的手段
    1、其他系统跳入电子印章平台的链接很多,难以管理
    2、其他的系统互相“登录”的情况很多,可以借鉴这个成功的模式
    3、前台登录不够安全
   
二、单点登录经过的大体步骤,以tcs-电子签章为例
    0、原本考虑仅对url的部分属性加密,但不足够安全,所以考虑web服务器代替用户进行登录的情况(这个思想很重要)
    1、用户在tcs系统中操作,当需要签章的时候,点击一个连接(想直接跳转到电子印章系统合同的电子签章页面),这个连接不指向电子签章系统,
        而是指向当前tcs的系统中的某个处理类A
    2、首先需要注册:  处理类A,从当前tcs系统中的session中取出,accountid(登录名),password(登录密码),主要使用.net的HttpWebRequest这个类,
        在tcs系统中的后台(也就是tcs的iis服务器)发送request请求B(后台发送请求,所以与当前浏览网页的用户的浏览器无关,甚至于这台
        客户端机器无关)
    3、电子印章系统类C在接受到请求B的时候,首先取出accountid、password进行正常登陆(验证用户是否存在,密码是否正确),
        然后查询出用户需要存入电子印章系统session中的那些数据O(权限和用户基本信息之类的数据)和request请求B中的其他一些数据,
        一并存入电子签章系统的context(应用上下文)中,以随机生成的长达20个字符的Key作为下标。并返回request请求这个Key,
        作为下次真正登录的钥匙。
    4、然后才是真正的登录:  tcs系统的处理类A发送request请求B后,电子印章系统返回了Key,此时,类A便可以根据这个Key,再次发起request请求D(这次发起请求与上次不一样
        这次是redict,是客户的浏览器进行redirct请求)进行真正的登录。
        电子印章系统类E在接收到请求D,form表单提交的(之所以用form表单提交,是因为,要将登录钥匙key也给隐藏掉)key后,
        到电子印章系统的context中,查找对应的信息O,如果找不到,则提示用户登录失败,如果找到则将信息从上下文中移入到当前
        登录用户(客户浏览器发送的请求)的session中。
    5、然后就是根据session中的信息O的某些信息(某些信息是tcs传入的,一般定义为一个数组)来进行不同的操作,如数组【0】可能是type,
        如果type==1,则跳转到签章列表,如果==2则跳转到印章申请等。。


主要代码如下,原理不多说,自己看:

.net核心类:

Imports System.Net
Imports System.IO
Imports System.Text

Public Class SingleLogin

    ''' <summary>
    ''' 单点登陆方法
    ''' </summary>
    ''' <param name="res">页面Response</param>
    ''' <param name="sRegUrl">注册Action</param>
    ''' <param name="sLoginUrl">登陆Action</param>
    ''' <param name="InfoList">参数集合</param>
    ''' <remarks></remarks>
    Public Shared Sub login(res As Web.HttpResponse, sRegUrl As String, sLoginUrl As String, InfoList As ArrayList)
        '验证用户&注册单点登录
        Dim sKey As String = registerSingleLogin(sRegUrl, InfoList)

        '单点登录
        signleLogin(res, sLoginUrl, sKey)
    End Sub

    ''' <summary>
    ''' 向Url传输信息,并Key
    ''' </summary>
    ''' <param name="sUrl">Url</param>
    ''' <param name="InfoList">传输数据</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Shared Function registerSingleLogin(sUrl As String, InfoList As ArrayList) As String
        Dim sAction As String = sUrl & "?params="
        For Each sItem As String In InfoList
            sAction += sItem & ","
        Next
        'sUrl.Remove(0, sUrl.Length - 1)
        sAction = sAction.Substring(0, sAction.Length - 1)
        Return sendRequest(sAction)
    End Function

    ''' <summary>
    ''' 发送Request请求
    ''' </summary>
    ''' <param name="url">Url</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Shared Function sendRequest(ByVal url As String) As String
        Dim request As HttpWebRequest = CType(WebRequest.Create(url), HttpWebRequest)
        request.Credentials = CredentialCache.DefaultCredentials

        Dim response As HttpWebResponse = CType(request.GetResponse(), HttpWebResponse)
        Dim receiveStream As Stream = response.GetResponseStream()
        Dim readStream As New StreamReader(receiveStream, Encoding.UTF8)

        Dim resultKey As String = readStream.ReadToEnd()
        response.Close()
        readStream.Close()
        Console.WriteLine(resultKey)
        Return resultKey
    End Function

    ''' <summary>
    ''' 单点登陆
    ''' </summary>
    ''' <param name="sUrl">Url</param>
    ''' <param name="sKey">Key</param>
    ''' <remarks></remarks>
    Private Shared Sub signleLogin(res As Web.HttpResponse, sUrl As String, sKey As String)
        sKey = sKey.Replace("""", "")
        If sKey.Length > 0 Then
            'Response.Redirect(url & "?key=" & sKey)
            Dim sHtml As String = ""
            sHtml = "<script type='text/javascript'>" & _
                "window.onload=function(){document.forms[0].submit();}" & _
                "</script>" & _
                "<form action='" & sUrl & "' style='display:none' method='post' target='_blank'>" & _
                "<input type='hidden' name='key' value='" & sKey & "'/>" & _
                "</form>"

            res.Write(sHtml)
            res.Flush()
        End If
    End Sub
End Class

.net系统单点登录java系统代码调用举例:

Protected Sub LinkButton1_Click(sender As Object, e As EventArgs) Handles LinkButton1.Click

        '1.访问 Signature 传输本系统Session中用户信息, Signature确认用户信息后,生成Key并返回。
        '2.跳转 Signature 并以Key进行登陆Signature。

        '传输本系统用户信息 AccountId,PassWord
        Dim InfoList As ArrayList = New ArrayList()

        'List Add 顺序不能错
        InfoList.Add("0") '其他信息1
        InfoList.Add("admin")' 用户名
        InfoList.Add("a12345")'密码
        InfoList.Add("cCode")'其他信息2

        Dim sRegUrl As String, sLoginUrl As String
        sRegUrl = System.Configuration.ConfigurationManager.AppSettings("Signature") & "/registerSingleSignon.action"
        sLoginUrl = System.Configuration.ConfigurationManager.AppSettings("Signature") & "/singleSignon.action"

        FY.SingleLogin.login(Response, sRegUrl, sLoginUrl, InfoList)

        'Response.Write("")
    End Sub

java系统为单点登录编写两个接口,一个注册、一个是登录:

  /**
     * 单点登录接口
     *
     * @return
     * @throws Exception
     */
    /**
     * , params = { "charSet", "UTF-8" }
     */
    @Action(value = "registerSingleSignon", results = {@Result(name = "success", type = "json", params = {
            "ignoreHierarchy", "false", "root", "key"})})
    public String registerSingleSignon() throws Exception {
        if (null == params || 0 >= params.length()) {
            key = "false,传入的params参数不能空";
            return SUCCESS;
        }
        key = loginService.registerSingleSignon(params);
        if (null == key) { // 没有这个用户,或者密码错误
            key = "false,没有这个用户或密码错误";
        }
        return SUCCESS;
    }

    /**
     * 单点登录 参数列表
     */
    private String singleParams;

    public String getSingleParams() {
        return singleParams;
    }

    public void setSingleParams(String singleParams) {
        this.singleParams = singleParams;
    }

    /**
     * 真正的单点登录
     *
     * @return
     * @throws Exception
     */
    @Action(value = "singleSignon", results = {
            @Result(name = "success", location = "/Main.jsp", type = "dispatcher"),
            @Result(name = "failed", location = "/index.jsp", type = "dispatcher")})
    public String singleSignon() throws Exception {
        LoginBo user = loginService.singleSignon(key);
        if (null == user) {
            setAccountError("单点登录出错了!可能的情况如下,请联系管理员!1、您已经使用此链接登录过一次;2、您的会话超时了;3、不能将连接copy到其他机子上使用;4、请您重新”服务器端登录“试试;5、密码错误");
        } else {
            logger.info("用户进行单点登录:" + user.getSysUsersEntity().getCaccountid());
            String[] paramArray = user.getParams();
            singleParams = JSONUtil.serialize(paramArray);
            if (null == paramArray || 0 >= paramArray.length) {
                setAccountError("发票签收单,服务器单点登录,传入params数组不正确");
            } else {
                return SUCCESS;
            }
        }
        return "failed";
    }

你可能感兴趣的:(异构单点登录)