`

java实现简单的单点登录(3)

阅读更多
3.2 WEB-SSO代码讲解
3.2.1身份认证服务代码解析
Web-SSO的源代码可以从网站地址http://gceclub.sun.com.cn/wangyu/web-sso/websso_src.zip下载。身份认证服务是一个标准的web应用,包括一个名为SSOAuthServlet,一个login.jsp文件和一个failed.html。身份认证的所有服务几乎都由SSOAuthServlet来实现了;login.jsp用来显示登录的页面(如果发现用户还没有登录过);failed.html是用来显示登录失败的信息(如果用户的用户名和密码与信息数据库中的不一样)。
SSOAuth的代码如下面的列表显示,结构非常简单,先看看这个Servlet的主体部分

 

package DesktopSSO;
 
import java.io.*;
import java.net.*;
import java.text.*;
import java.util.*;
import java.util.concurrent.*;
 
import javax.servlet.*;
import javax.servlet.http.*;
 
 
public class SSOAuth extends HttpServlet {
   
    static private ConcurrentMap accounts;
    static private ConcurrentMap SSOIDs;
    String cookiename="WangYuDesktopSSOID";
    String domainname;
   
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        domainname= config.getInitParameter("domainname");
        cookiename = config.getInitParameter("cookiename");
        SSOIDs = new ConcurrentHashMap();
        accounts=new ConcurrentHashMap();
        accounts.put("wangyu", "wangyu");
        accounts.put("paul", "paul");
        accounts.put("carol", "carol");
    }
 
    protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        PrintWriter out = response.getWriter();
        String action = request.getParameter("action");
        String result="failed";
        if (action==null) {
            handlerFromLogin(request,response);
        } else if (action.equals("authcookie")){
            String myCookie = request.getParameter("cookiename");
            if (myCookie != null) result = authCookie(myCookie);
            out.print(result);
            out.close();
        } else if (action.equals("authuser")) {
           result=authNameAndPasswd(request,response);
            out.print(result);
            out.close();
        } else if (action.equals("logout")) {
            String myCookie = request.getParameter("cookiename");
            logout(myCookie);
            out.close();
        }
    }
 
.....
 
}
 
从代码很容易看出,SSOAuth就是一个简单的Servlet。其中有两个静态成员变量:accountsSSOIDs,这两个成员变量都使用了JDK1.5中线程安全的MAP类: ConcurrentMap,所以这个样例一定要JDK1.5才能运行。Accounts用来存放用户的用户名和密码,在init()的方法中可以看到我给系统添加了三个合法的用户。在实际应用中,accounts应该是去数据库中或LDAP中获得,为了简单起见,在本样例中我使用了ConcurrentMap在内存中用程序创建了三个用户。而SSOIDs保存了在用户成功的登录后所产生的cookie和用户名的对应关系。它的功能显而易见:当用户成功登录以后,再次访问别的系统,为了鉴别这个用户请求所带的cookie的有效性,需要到SSOIDs中检查这样的映射关系是否存在。
 
在主要的请求处理方法processRequest()中,可以很清楚的看到SSOAuth的所有功能
  1. 如果用户还没有登录过,是第一次登录本系统,会被跳转到login.jsp页面(在后面会解释如何跳转)。用户在提供了用户名和密码以后,就会用handlerFromLogin()这个方法来验证。
  2. 如果用户已经登录过本系统,再访问别的应用的时候,是不需要再次登录的。因为浏览器会将第一次登录时产生的cookie和请求一起发送。效验cookie的有效性是SSOAuth的主要功能之一。
  3. SSOAuth还能直接效验非login.jsp页面过来的用户名和密码的效验请求。这个功能是用于非web应用的SSO,这在后面的桌面SSO中会用到。
  4. SSOAuth还提供logout服务。
 
下面看看几个主要的功能函数:
private void handlerFromLogin(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String pass = (String)accounts.get(username);
        if ((pass==null)||(!pass.equals(password)))
            getServletContext().getRequestDispatcher("/failed.html").forward(request, response);
        else {
            String gotoURL = request.getParameter("goto");
            String newID = createUID();
            SSOIDs.put(newID, username);
            Cookie wangyu = new Cookie(cookiename, newID);
            wangyu.setDomain(domainname);
            wangyu.setMaxAge(60000);
            wangyu.setValue(newID);
            wangyu.setPath("/");
            response.addCookie(wangyu);
            System.out.println("login success, goto back url:" + gotoURL);
            if (gotoURL != null) {
                PrintWriter out = response.getWriter();
                response.sendRedirect(gotoURL);
                out.close();
            }
        }  
    }
 
handlerFromLogin()这个方法是用来处理来自login.jsp的登录请求。它的逻辑很简单:将用户输入的用户名和密码与预先设定好的用户集合(存放在accounts中)相比较,如果用户名或密码不匹配的话,则返回登录失败的页面(failed.html),如果登录成功的话,需要为用户当前的session创建一个新的ID,并将这个ID和用户名的映射关系存放到SSOIDs中,最后还要将这个ID设置为浏览器能够保存的cookie值。
登录成功后,浏览器会到哪个页面呢?那我们回顾一下我们是如何使用身份认证服务的。一般来说我们不会直接访问身份服务的任何URL,包括login.jsp。身份服务是用来保护其他应用服务的,用户一般在访问一个受SSOAuth保护的Web应用的某个URL时,当前这个应用会发现当前的用户还没有登录,便强制将也页面转向SSOAuthlogin.jsp,让用户登录。如果登录成功后,应该自动的将用户的浏览器指向用户最初想访问的那个URL。在handlerFromLogin()这个方法中,我们通过接收goto”这个参数来保存用户最初访问的URL,成功后便重新定向到这个页面中。
另外一个要说明的是,在设置cookie的时候,我使用了一个setMaxAge(6000)的方法。这个方法是用来设置cookie的有效期,单位是秒。如果不使用这个方法或者参数为负数的话,当浏览器关闭的时候,这个cookie就失效了。在这里我给了很大的值(1000分钟),导致的行为是:当你关闭浏览器(或者关机),下次再打开浏览器访问刚才的应用,只要在1000分钟之内,就不需要再登录了。我这样做是下面要介绍的桌面SSO中所需要的功能。
其他的方法更加简单,这里就不多解释了。
 
3.2.2具有SSO功能的web应用源代码解析
要实现WEB-SSO的功能,只有身份认证服务是不够的。这点很显然,要想使多个应用具有单点登录的功能,还需要每个应用本身的配合:将自己的身份认证的服务交给一个统一的身份认证服务-SSOAuthSSOAuth服务中提供的各个方法就是供每个加入SSOWeb应用来调用的。
一般来说,Web应用需要SSO的功能,应该通过以下的交互过程来调用身份认证服务的提供的认证服务:
  • Web应用中每一个需要安全保护的URL在访问以前,都需要进行安全检查,如果发现没有登录(没有发现认证之后所带的cookie),就重新定向到SSOAuth中的login.jsp进行登录。
  • 登录成功后,系统会自动给你的浏览器设置cookie,证明你已经登录过了。
  • 当你再访问这个应用的需要保护的URL的时候,系统还是要进行安全检查的,但是这次系统能够发现相应的cookie
  • 有了这个cookie,还不能证明你就一定有权限访问。因为有可能你已经logout,或者cookie已经过期了,或者身份认证服务重起过,这些情况下,你的cookie都可能无效。应用系统拿到这个cookie,还需要调用身份认证的服务,来判断cookie时候真的有效,以及当前的cookie对应的用户是谁。
  • 如果cookie效验成功,就允许用户访问当前请求的资源。
以上这些功能,可以用很多方法来实现:
  • 在每个被访问的资源中(JSPServlet)中都加入身份认证的服务,来获得cookie,并且判断当前用户是否登录过。不过这个笨方法没有人会用:-)
  • 可以通过一个controller,将所有的功能都写到一个servlet中,然后在URL映射的时候,映射到所有需要保护的URL集合中(例如*.jsp/security/*等)。这个方法可以使用,不过,它的缺点是不能重用。在每个应用中都要部署一个相同的servlet
  • Filter是比较好的方法。符合Servlet2.3以上的J2EE容器就具有部署filter的功能。(Filter的使用可以参考JavaWolrd的文章http://www.javaworld.com/javaworld/jw-06-2001/jw-0622-filters.htmlFilter是一个具有很好的模块化,可重用的编程API,用在SSO正合适不过。本样例就是使用一个filter来完成以上的功能。
package SSO;
 
import java.io.*;
import java.net.*;
import java.util.*;
import java.text.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.*;
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.methods.GetMethod;
 
public class SSOFilter implements Filter {
    private FilterConfig filterConfig = null;
    private String cookieName="WangYuDesktopSSOID";
    private String SSOServiceURL= "http://wangyu.prc.sun.com:8080/SSOAuth/SSOAuth";
    private String SSOLoginPage= "http://wangyu.prc.sun.com:8080/SSOAuth/login.jsp";
   
    public void init(FilterConfig filterConfig) {
 
        this.filterConfig = filterConfig;
        if (filterConfig != null) {
            if (debug) {
                log("SSOFilter:Initializing filter");
            }
        }       
        cookieName = filterConfig.getInitParameter("cookieName");
        SSOServiceURL = filterConfig.getInitParameter("SSOServiceURL");
        SSOLoginPage = filterConfig.getInitParameter("SSOLoginPage");
    } 
.....
.....
 
}
 
以上的初始化的源代码有两点需要说明:一是有两个需要配置的参数SSOServiceURLSSOLoginPage。因为当前的Web应用很可能和身份认证服务(SSOAuth)不在同一台机器上,所以需要让这个filter知道身份认证服务部署的URL,这样才能去调用它的服务。另外一点就是由于身份认证的服务调用是要通过http协议来调用的(在本样例中是这样设计的,读者完全可以设计自己的身份服务,使用别的调用协议,如RMISOAP等等),所有笔者引用了apachecommons工具包(详细信息情访问apache 的网站http://jakarta.apache.org/commons/index.html),其中的httpclient”可以大大简化http调用的编程。
下面看看filter的主体方法doFilter():
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        if (debug) log("SSOFilter:doFilter()");
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        String result="failed";
        String url = request.getRequestURL().toString();
        String qstring = request.getQueryString();
        if (qstring == null) qstring ="";
 
        //检查http请求的head是否有需要的cookie
        String cookieValue ="";
        javax.servlet.http.Cookie[] diskCookies = request.getCookies();
        if (diskCookies != null) {
            for (int i = 0; i < diskCookies.length; i++) {
                if(diskCookies[i].getName().equals(cookieName)){
                    cookieValue = diskCookies[i].getValue();
 
                    //如果找到了相应的cookie则效验其有效性
                    result = SSOService(cookieValue);
                    if (debug) log("found cookies!");
                }
            }
        }
        if (result.equals("failed")) { //效验失败或没有找到cookie,则需要登录
            response.sendRedirect(SSOLoginPage+"?goto="+url);
        } else if (qstring.indexOf("logout") > 1) {//logout服务
            if (debug) log("logout action!");
            logoutService(cookieValue);
            response.sendRedirect(SSOLoginPage+"?goto="+url);
        } else {//效验成功
            request.setAttribute("SSOUser",result);
            Throwable problem = null;
            try {
                chain.doFilter(req, res);
            } catch(Throwable t) {
                problem = t;
                t.printStackTrace();
            }      
            if (problem != null) {
                if (problem instanceof ServletException) throw (ServletException)problem;
                if (problem instanceof IOException) throw (IOException)problem;
                sendProcessingError(problem, res);
            }
        }  
    }
 
doFilter()方法的逻辑也是非常简单的,在接收到请求的时候,先去查找是否存在期望的cookie值,如果找到了,就会调用SSOService(cookieValue)去效验这个cookie的有效性。如果cookie效验不成功或者cookie根本不存在,就会直接转到登录界面让用户登录;如果cookie效验成功,就不会做任何阻拦,让此请求进行下去。在配置文件中,有下面的一个节点表示了此filterURL映射关系:只拦截所有的jsp请求。
<filter-mapping>
<filter-name>SSOFilter</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
 
下面还有几个主要的函数需要说明:
private String SSOService(String cookievalue) throws IOException {
        String authAction = "?action=authcookie&cookiename=";
        HttpClient httpclient = new HttpClient();
        GetMethod httpget = new GetMethod(SSOServiceURL+authAction+cookievalue);
        try { 
            httpclient.executeMethod(httpget);
            String result = httpget.getResponseBodyAsString();
            return result;
        } finally {
            httpget.releaseConnection();
        }
    }
   
    private void logoutService(String cookievalue) throws IOException {
        String authAction = "?action=logout&cookiename=";
        HttpClient httpclient = new HttpClient();
        GetMethod httpget = new GetMethod(SSOServiceURL+authAction+cookievalue);
        try {
            httpclient.executeMethod(httpget);
            httpget.getResponseBodyAsString();
        } finally {
            httpget.releaseConnection();
        }
    }
 
这两个函数主要是利用apache中的httpclient访问SSOAuth提供的认证服务来完成效验cookielogout的功能。
其他的函数都很简单,有很多都是我的IDENetBeans)替我自动生成的。
分享到:
评论

相关推荐

    JAVA单点登录的实现

    1,通过session会话来判断 2,实现单点登录

    JAVA实现单点登录功能

    JAVA 实现单点登录功能 ! 包含 所有的详细文档 ! 试用手册值得学习

    最新java实现简单的单点登录

    在提供的压缩包"最新java实现简单的单点登录.doc"中,可能包含了关于如何使用Java Web和Spring Security实现SSO的具体步骤、配置代码示例和常见问题解答等内容。读者可以通过阅读这份文档,进一步了解和学习如何在...

    基于Java集成CAS单点登录【接部署即可启用】

    基于Java中CAS的单点登录,有服务端的所有源码,将tomcat目录下的所有资源直接拷到Tomcat服务中间件的webapp目录下,阅读tomcat-webapp中的read.txt文档,查看使用说明,适用于第一次开发CAS单点登录的同学们,简单...

    java实现简单的单点登录

    间接授权通过令牌实现,sso认证中心验证用户的用户名密码没问题,创建授权令牌,在接下来的跳转过程中,授权令牌作为参数发送给各个子系统,子系统拿到令牌,即得到了授权,可以借此创建局部会话,局部会话登录方式...

    用Java实现单点登录

    单点登录(Single Sign-...以上就是Java实现单点登录的一些关键知识点,每个方面都需要深入了解和恰当配置,以构建一个安全、高效的SSO系统。实际开发过程中,还需要结合业务场景,考虑性能、扩展性和用户体验等因素。

    java跨域单点登录实现

    Java跨域单点登录(Single Sign-On,SSO)实现是一项关键的系统集成技术,它允许用户在多个应用系统中只需登录一次,就能访问所有相互信任的应用系统,无需再次进行身份验证。本项目代码着重展示了如何在Java环境中...

    java实现单点登录_图例及相关代码

    3. 使用 Java EE 实现单点登录系统。 Java 实现单点登录的应用场景包括: 1. 企业应用集成(EAI):单点登录系统可以应用于企业应用集成中,以降低管理的消耗和提高安全性。 2. 面向服务的架构(SOA):单点登录...

    跨服务器登录验证(单点登录SSO)的过程和Java实现

    跨服务器登录验证(单点登录SSO)的过程和Java实现 跨服务器登录验证(单点登录SSO)是指用户只需要登录一次便可以访问多个相关的应用系统的机制。这种机制可以提高用户体验和系统安全性。下面我们将介绍跨服务器...

    微博Oauth2.0 协议用java 实现单点登录获取用户信息

    在Java中实现微博的单点登录(Single Sign-On, SSO)功能,涉及到的主要步骤包括注册应用、获取授权码、交换访问令牌、获取用户信息等。下面我们将详细探讨这些过程。 1. **注册应用**: 在开始实现之前,你需要在...

    java单点登录流程及其他

    在 Java 中实现单点登录需要使用到 Jwt(JSON Web Tokens),Jwt 是一种基于 Token 的身份验证机制,可以与 SSO 一起使用,但并不是 SSO 的必要组成部分。 首先,我们需要配置 SecurityConfig 类,该类是 Spring ...

    java实现可跨浏览器单点登录

    单点登录(Single Sign On,简称SSO)是一种身份验证机制,允许用户在一次登录后,无需再次输入凭证即可访问多个相互信任的应用系统。在Java环境下实现SSO,可以为企业的信息化管理提供便利,减少用户的登录操作,...

    shiro+spring+data+session+redis实现单点登录

    本案例聚焦于使用Apache Shiro、Spring、Spring Data以及Redis来实现单点登录功能,下面将详细解释这些组件以及它们如何协同工作。 **Apache Shiro** Apache Shiro是一款轻量级的安全框架,提供了认证、授权、会话...

    java应用系统单点登录

    它通过共享Session和Cookie来实现单点登录。在Shiro中,可以通过配置Realm(域)来对接不同的认证源,如数据库、LDAP、CAS等。 4. **JWT(JSON Web Token)**: JWT是一种开放标准,用于在网络应用之间安全地传输...

    spring+springMvc简单实现SSO单点登录

    利用springMvc 实现的简单的单点登录Demo,内含三个小Mavn项目分别是 1、认证中心SSOServer 2、子系统1SSOClient1 3、子系统2SSOClient2 文章请参考 http://blog.csdn.net/qq_31183297/article/details/79419222

    "java实现简单的单点登录"源码包

    http://www.blogjava.net/xcp/archive/2010/04/13/318125.html 页面的源码地址无法访问,我在其他地方找到了。可以运行的三个简单应用,配置完成后可以实现单点登录,供初学者研究其原理。

    Java实现基于KeyCloak的单点登录权限管理POC验证源码.zip

    Java实现基于KeyCloak的单点登录权限管理POC验证源码.zipJava实现基于KeyCloak的单点登录权限管理POC验证源码.zipJava实现基于KeyCloak的单点登录权限管理POC验证源码.zipJava实现基于KeyCloak的单点登录权限管理POC...

    java-cas单点登录服务端

    CAS(Central Authentication Service)是一款不错的针对 Web 应用的单点登录框架,本文介绍了 CAS 的原理、协议、在 Tomcat 中的配置和使用,研究如何采用 CAS 实现轻量级单点登录解决方案。 CAS 是 Yale 大学发起的...

    rtx单点登录(JAVA实现)

    jsp实现RXT单点登录,单点登录要求在OA服务器安装Server SDK开发包,同时需要配置RTX服务器安装目录下的AppConnConfig.xml文件,把OA服务器的IP地址加进来,例如OA服务器地址为172.30.21.20,配置如下所示: ...

    基于Java EE的单点登录技术研究与实现.pdf

    研究者赵向梅在其论文《基于Java EE的单点登录技术研究与实现》中,设计并仿真实现了这两种单点登录系统,并证明了该系统能够有效解决当前Web应用系统面临的登录问题。通过使用Java EE平台的特性,实现了一个高效、...

Global site tag (gtag.js) - Google Analytics