java单点登录(SSO)的实现

 更新时间:2021年07月15日 09:43:03   作者:疯狂打码  
SSO是指在多个应用系统中个,用户只需要登陆一次就可以访问所有相互信任的应用系统,本文主要介绍了java单点登录的实现,具有一定的参考价值,感兴趣的可以了解一下

单点登录(SSO):SSO是指在多个应用系统中个,用户只需要登陆一次就可以访问所有相互信任的应用系统。它包括可以将这次主要的登录映射到其他应用中用于同一用户的登陆的机制。

SSO的实现过程:

通过上述图形,我们可以看到SSO的大体实现步骤主要分为两大步:存储登录信息,查验登录信息。

对于SSO,我们也可以将之分为两大不同的类型:同域SSO和跨域SSO;其中同域SSO又可以分为完全同域SSO和同父域SSO。

一、完全同域SSO:指的是域名完全相同的多个应用系统中实现单点登录。

其实现步骤主要分为:前期准备工作,编写统一登录接口,编写登录校验接口,编写验证页面,实现SSO;

编写统一登录接口:
登录页面的编写主要是录入用户的登录信息,包括用户名,密码,以及登录页面的地址。因为存在多个应用系统,所以用户在统一登录页面登陆成功后,系统需要知道用户想要访问的是哪个系统页面,这个时候就需要记录用户第一次访问的地址,等到用户登录成功后,就可直接跳转该页面。

<body>
    <center>
        <h1>请登录</h1>
        <form action="/sso/doLogin.action" method="POST">
            <span>用户名:</span><input type="text" name="username" />
            <span>密码:</span><input type="text" name="password" />
            //暂存需要登录页面的url地址
            <input type="hidden" name="gotoUrl" value="${gotoUrl}" />
            <input type="submit" />
        </form>
    </center>
</body>

登录方法的编写:需要新建cookie,将用户的信息存进cookie中,并指定cookie的路径,因为是完全同域,所以cookie的地址可以简写为(“/”)。这里必须要设置cookie的路径,如果不设置,那么cookie的路径将并不一定在当前域名的顶层,它有可能就在当前的这个路径下才可见,这样会导致在当前域的其他路径下找不到这个cookie,解决办法就是把cookie设置到当前域的最顶层域里面,这样当前域下的所有应用就会都可见。

public String doLogin(){
        //新建Cookie
        Cookie cookie = new Cookie("ssocookie","sso");
        //设置Cookie路径
        cookie.setPath("/");
        HttpServletResponse response = ServletActionContext.getResponse();
        response.addCookie(cookie);
        return "success";
 }

登录校验接口的编写:通常SSO登录接口校验都会放在登录拦截器中,当用户想要访问某个系统时,登录拦截器将直接重定向到统一登录页面,用户填写完登录信息后,就会进行登录校验。

//cookie校验(放在拦截器中进行校验)
    public static boolean checkCookie(HttpServletRequst request){
        Cookie[] cookies=request.getCookies();
        if(cookies!=null){
            for(Cookies cookie:cookies){
                if(cookie.getName().equals("ssocookie")
                        &&cookie.getValue().equals("sso")){
                    return true;
                }
            }
        }
        return false;
  }

编写测试主页

public String main(){
        HttpServletRequst request = ServletActionContext.getRequst();
        if(SSOCheck.checkCookie(request)){
            //登陆成功,记录用户登录信息......
            return "success";
        }
        //登录失败,暂存需要访问的地址,登录成功后,直接访问该地址
        gotoUrl="/demo1/main.action";
        return "login";
 }

最后还有struts2的配置文件

<struts>
    <package name="sso" namespace="/sso" extends="struts-default">
        <action name="doLogin" class="com.xm.controllerAction.SSOAction" method="doLogin">
       <!-- 用户登录成功后,需要进行重定向,重新跳转到用户最初访问的路径 -->  
            <result name="success" type="redirect">${gotoUrl}</result>
        </action>
    </package>
    
    <package name="demo1" namespace="/demo1" extends="struts-default">
        <action name="main" class="com.xm.controllerAction.Demo1Action" method="main">
            <result name="success">/success1.jsp</result>
            <result name="login">/login.jsp</result>
        </action>
    </package>
    <package name="demo2" namespace="/demo2" extends="struts-default">
        <action name="main" class="com.xm.controllerAction.Demo2Action" method="main">
            <result name="success">/success2.jsp</result>
            <result name="login">/login.jsp</result>
        </action>
    </package>
</struts>

二、同父域SSO:指的是父域名相同的应用系统上实现SSO。

其实现步骤与上述完全同域SSO相同。

其中检验域名:http://check.x.com

测试页面域名:http://demo1.x.com和http://demo2.x.com

编写统一登录接口:
代码实现与完全同域名SSO基本一致,不过在设置提交路径时,因为二级域名不同,所以不能写成相对路径,需要写成绝对路径地址。

<body>
    <center>
        <h1>请登录</h1>
     //表单提交地址需写成绝对路径,不能写相对路径
        <form action="http://check.x.com/sso/doLogin.action" method="POST">
            <span>用户名:</span><input type="text" name="username" />
            <span>密码:</span><input type="text" name="password" />
            //暂存需要登录页面的url地址
            <input type="hidden" name="gotoUrl" value="${gotoUrl}" />
            <input type="submit" />
        </form>
    </center>
</body>

登录方法:在设置cookie路径的时候有所变化,同上,为了使得当前两个同父域的应用系统都可见这个cookie,那么我们需要将这个cookie设置到父域下面,而不应该设置到本域下面,这样才可以实现域不同,但是父域相同的应用都可以看到的这个cookie。

   public String doLogin(){
     boolean ok = SSOCheck.checkLogin(userName,passWord);
     if(ok){
          //新建Cookie
          Cookie cookie = new Cookie("ssocookie","sso");
          //设置Cookie的父域
          cookie.setDomain(".x.com");
          //设置Cookie路径
          cookie.setPath("/");
          HttpServletResponse response = ServletActionContext.getResponse();
          response.addCookie(cookie);
          return "success";
     }
  }

登录校验接口:因为有着不同的域,所以我们应该将登录所获得cookie传到专门的校验域下的校验方法中进行校验,否则我们需要在各自不同的登录页面实现校验,这样显得代码十分的冗余。

    private String cookieName;
    private String cookieValue;
    public String getCookieName() {
      return cookieName;
    }
    public void setCookieName(String cookieName) {
      this.cookieName = cookieName;
    }
    public String getCookieValue() {
      return cookieValue;
    }
    public void setCookieValue(String cookieValue) {
      this.cookieValue = cookieValue;
    }


   //二级域名向二级域名发送请求
    public void checkCookie() throws IOException{
        boolean ok=SSOCheck.checkCookie(cookieName,cookieValue);
        String result="0";
        if(ok){
            result="1";
        }
        HttpServletResponse response = ServletActionContext.getResponse();
        response.getWriter().print(result);
        response.getWriter().close();
    }


public static boolean checkCookie(String cookieName,String cookieValue){
        if(cookieName.equals("ssocookie")&&cookieValue.equals("sso")){
            return true;
        }
        return false;
    }

编写测试主页

public String main(){
        HttpServletRequst request = ServletActionContext.getRequst();
     //获取cookie
        Cookie[] cookies=request.getCookies();
        if(cookies!=null){
            for(Cookie cookie:cookies){
                if(cookie.getName().equals("ssocookie")){
            //向检验服务器中发送cookieName和cookieValue
                    String result = Demo1Tool.doGet("http://check.x.com/so/checkCookie.action",
                            cookie.getName(),cookie.getValue());
                    if(result.equals("1")){
                        return "success";
                    }
                }
            }
        }
        //暂存需要访问的地址,登录成功后,直接访问该地址
        gotoUrl="http://demo1.x.com/demo1/main.action";
        return "login";
}

public static String doGet(String url,String cookieName,String cookieValue){
        //定义返回值
        StringBuffer sb = new StringBuffer();
        HttpURLConnection httpURLConnection = null;
        try{
            //校验方法所在的地址
            URL urls = new URL(url+
                    "?cookieName="+cookieName+"&cookieValue="+cookieValue);
            //打开连接
            httpURLConnection = (HttpURLConnection) urls.openConnection();
            //设置打开连接的方法
            httpURLConnection.setRequestMethod("GET");
            //开始连接
            httpURLConnection.connect();
            InputStream in = httpURLConnection.getInputStream();
            InputStreamReader isr = new InputStreamReader(in);
            BufferedReader br = new BufferedReader(isr);
            String temp = null;
            while((temp = br.readLine())!=null){
                sb.append(temp);
            }
            br.close();
            isr.close();
            in.close();
        } catch(IOException e){
            e.printStackTrace();
        } finally{
            if(httpURLConnection!=null){
                httpURLConnection.disconnect();
            }
        }
        return sb.toString();
}

struts配置文件

<struts>
    <package name="sso" namespace="/sso" extends="struts-default">
        <action name="doLogin" class="com.xm.controllerAction.SSOAction" method="doLogin">
            <result name="success" type="redirect">${gotoUrl}</result>
        </action>
        <action name="checkCookie" class="check.x.com.SSOAction" method="checkCookie">
        </action>
    </package>
    <package name="demo1" namespace="/demo1" extends="struts-default">
        <action name="main" class="demo1.x.com.Demo1Action" method="main">
            <result name="success">/success1.jsp</result>
            <result name="login">/login.jsp</result>
        </action>
    </package>
    <package name="demo2" namespace="/demo2" extends="struts-default">
        <action name="main" class="demo2.x.com.Demo2Action" method="main">
            <result name="success">/success2.jsp</result>
            <result name="login">/login.jsp</result>
        </action>
    </package>
</struts>

三、跨域SSO:在域名完全不同的应用程序上实现SSO。

其实现步骤与完全同域SSO相同。

其中检验域名:http://www.x.com

测试页面域名:http://www.a.com和http://www.b.com

编写统一登录接口:

<body>
    <center>
        <h1>请登录</h1>
        //这里需要向当前所在的域提交申请,因为如果向校验域提交申请,那么在本域中将无法看到cookie
        <form action="/${path}/doLogin.action" method="POST">
            <span>用户名:</span><input type="text" name="username" />
            <span>密码:</span><input type="text" name="password" />
            //暂存需要登录页面的url地址
            <input type="hidden" name="gotoUrl" value="${gotoUrl}" />
            <input type="submit" />
        </form>
    </center>
</body>

登录方法:

public String doLogin(){
        Map<String,String> map = new HashMap<String,String>();
        map.put("userName", userName);
        map.put("password", passWord);
        String result = Demo1Tool.doGet("http://www.x.com/sso/doLogin.action",map);
        if(result.equals("1")){
            return "success";
        }
        return "login";
}

public void doLogin() throw IOException{
        boolean ok=SSOCheck.checkCookie(cookieName,cookieValue);
        String result = "0";
        if(ok){
            result = "1";
        }
        HttpServletResponse response = ServletActionContext.getResponse();
        response.getWriter().print(result);
        response.getWriter().close();
}

登录校验接口;和同父域SSO的登录校验基本一致,没有什么变化。

public void checkCookie() throws IOException{
        boolean ok=SSOCheck.checkCookie(cookieName,cookieValue);
        String result="0";
        if(ok){
            result="1";
        }
        HttpServletResponse response = ServletActionContext.getResponse();
        response.getWriter().print(result);
        response.getWriter().close();
}

编写测试主页

public String main(){
        HttpServletRequst request = ServletActionContext.getRequst();
        Cookie[] cookies=request.getCookies();
        if(cookies!=null){
            for(Cookie cookie:cookies){
                if(cookie.getName().equals("ssocookie")){
                    Map<String,String> map = new HashMap<String,String>();
                    map.put("userName", cookie.getName());
                    map.put("password", cookie.getValue());
                    String result = Demo1Tool.doGet("http://www.x.com/so/checkCookie.action",
                            cookie.getName(),cookie.getValue());
                    if(result.equals("1")){
                        return "success";
                    }
                }
            }
        }
        //暂存需要访问的地址,登录成功后,直接访问该地址
        path = "demo1";
        gotoUrl="http://www.a.com/demo1/main.action";
        return "login";
    }

public static String doGet(String url,Map<String,String> map){
        //定义返回值
        StringBuffer sb = new StringBuffer();
        HttpURLConnection httpURLConnection = null;
        try{
            StringBuffer t_s = new StringBuffer(url).append("?");
            for(Map.Entry<String, String> entry:map.entrySet()){
                t_s.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
                
            }
            url = t_s.substring(0,t_s.length()-1);
            //校验方法所在的地址
            URL urls = new URL(url);
            //打开连接
            httpURLConnection = (HttpURLConnection) urls.openConnection();
            //设置打开连接的方法
            httpURLConnection.setRequestMethod("GET");
            //开始连接
            httpURLConnection.connect();
            InputStream in = httpURLConnection.getInputStream();
            InputStreamReader isr = new InputStreamReader(in);
            BufferedReader br = new BufferedReader(isr);
            String temp = null;
            while((temp = br.readLine())!=null){
                sb.append(temp);
            }
            br.close();
            isr.close();
            in.close();
        } catch(IOException e){
            e.printStackTrace();
        } finally{
            if(httpURLConnection!=null){
                httpURLConnection.disconnect();
            }
        }
        return sb.toString();
    }

至此,准备工作做完,接下来是跨域SSO实现中最重要的部分,也就是cookie的设置,在之前完全同域和同父域的情况下,为了实现SSO,我们在进行doLogin时就设置了cookie,因为域名相同,所以十分简单,但是在跨域SSO中,因为不同域之间的cookie是不可见的,所以我们不可能只设置一个cookie,然后令所有的域名下的应用程序皆可见,所以我们应该在每个域下面都有着为本域设置cookie的方法,而不应该直接将设置cookie交给校验域。

//为本域设置cookie的方法
    public void addCookie(){
        Cookie cookie = new Cookie("ssocookie","sso");
        cookie.setPath("/");
        HttpServletResponse response = ServletActionContext.getResponse();
        response.addCookie(cookie);
    }

还需要在配置文件中进行配置:

<action name="addCookie" class="www.a.com.Demo1Action" method="addCookie"></action>

写完好方法,则需要进行调用,因此我们需要找一个可以让二者进行交会的地方,在这里我选择了登录成功的瞬间,通过隐藏的Iframe让二者进行交会。

public String doLogin(){
        Map<String,String> map = new HashMap<String,String>();
        map.put("userName", userName);
        map.put("password", passWord);
        String result = Demo1Tool.doGet("http://www.x.com/sso/doLogin.action",map);
        if(result.equals("1")){
            return "success";
        }
        List hidderUrl = new ArrayList<String>();
        hidderUrl.add("http://www.a.com/demo1/addCookie.action");
        hidderUrl.add("http://www.b.com/demo2/addCookie.action");
        return "login";
    }
<c:forEach var="url" item="${hiddenUrl}">
    <iframe src="${url}" width="0px" heigth="0px" style="display:none"></iframe>
</c:forEach>

到此这篇关于java单点登录(SSO)的实现的文章就介绍到这了,更多相关java单点登录内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解java中List中set方法和add方法的区别

    详解java中List中set方法和add方法的区别

    本文主要介绍了详解java中List中set方法和add方法的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08
  • Java BigDecimal使用及基本运算(推荐)

    Java BigDecimal使用及基本运算(推荐)

    Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算。这篇文章主要介绍了Java BigDecimal使用指南针(推荐),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-08-08
  • 2020新版idea创建项目没有javaEE 没有Web选项的完美解决方法

    2020新版idea创建项目没有javaEE 没有Web选项的完美解决方法

    这篇文章主要介绍了2020新版idea创建项目没有javaEE 没有Web选项的完美解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-09-09
  • springboot html调用js无效400问题及解决

    springboot html调用js无效400问题及解决

    这篇文章主要介绍了springboot html调用js无效400的问题及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • java中字符串如何计算字节长度

    java中字符串如何计算字节长度

    这篇文章主要介绍了java中字符串如何计算字节长度,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-10-10
  • 浅谈在Java中使用Callable、Future进行并行编程

    浅谈在Java中使用Callable、Future进行并行编程

    这篇文章主要介绍了浅谈在Java中使用Callable、Future进行并行编程,具有一定借鉴价值,需要的朋友可以参考下。
    2017-12-12
  • 浅谈Spring中的循环依赖问题与解决方案

    浅谈Spring中的循环依赖问题与解决方案

    这篇文章主要介绍了浅谈Spring中的循环依赖问题与解决方案,循环依赖就是两个或则两个以上的bean互相持有对方,最终形成闭环,比如A依赖于B,B依赖于C,C又依赖于A,需要的朋友可以参考下
    2023-12-12
  • Java开发人员最常犯的10个错误

    Java开发人员最常犯的10个错误

    这篇文章主要介绍了Java开发人员最常犯的10个错误,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-07-07
  • java并发数据包Exchanger线程间的数据交换器

    java并发数据包Exchanger线程间的数据交换器

    这篇文章主要为大家介绍了java并发数据包使用数据交换器Exchanger来进行线程之间的数据交换。有需要的朋友可以借鉴参考下,希望能够有所帮助
    2022-03-03
  • 详解Java8中接口的默认方法和静态方法

    详解Java8中接口的默认方法和静态方法

    Java 8是Java语言的一个重要版本,其中引入了许多新特性和改进,其中一个值得关注的特性是接口的默认方法和静态方法,本文就来和大家简单讲讲吧
    2023-05-05

最新评论