最新公告
  • 欢迎您光临极客文库,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入我们
  • Server实现

    1、页面我们仿照慕课网的页面进行设计,这里已经准备好了登录页面,将login.jsp拷贝到SSO_Server里的views里面。

    2、在com.jikewenku.sso.servlet包下面新建一个LoginServelet.java

    package com.jikewenku.sso.servlet;
    
    import javax.servlet.ServletConfig;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.util.Objects;
    import java.util.UUID;
    
    
    public class LoginServlet extends HttpServlet {
    
        private String domains;
    
        @Override
        public void init(ServletConfig config) throws ServletException {
            super.init(config);
            domains = config.getInitParameter("domains");
        }
    
        @Override
        protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //此语句表示当request.getServletPath()的值是/login时就是登录操作
            if (Objects.equals("/login", request.getServletPath())) {
                String username = request.getParameter("username");
                String password = request.getParameter("password");
    
                String source = request.getParameter("source");
    
                if (null == source || Objects.equals("", source)) {
                    String referer = request.getHeader("referer");
                    source = referer.substring(referer.indexOf("source=") + 7);
                }
    
                if (Objects.equals(username, password)) {
                    //使用UUID.randomUUID().toString()会得到一个由字母数组组成,用-链接的随机字符串,使用replace()方法去掉
                    String ticket = UUID.randomUUID().toString().replace("-", "");
                    System.out.println("******************************:" + ticket);
                    response.sendRedirect(source + "/main?ticket=" + ticket + "&domains=" +
                            domains.replace(source + ",", "").replace("," + source, "").replace(source, ""));
                } else {
                    request.setAttribute("source", source);
                    request.getRequestDispatcher("/WEB-INF/views/login.jsp").forward(request, response);
                }
            } else if (Objects.equals("/ssoLogin", request.getServletPath())) {
                request.getRequestDispatcher("/WEB-INF/views/login.jsp").forward(request, response);
            } else if (Objects.equals("/ssoLogout", request.getServletPath())) {
                String source = request.getParameter("source");
    
                //由于用户信息没有存储在内存或者类似memcache这样的缓存中,所以这里没有相关的助理
                //在ssoLogout请求时,传过来当前的用户名,根据用户名查找内存或者缓存,删除相应信息,以完成退出
                //用户从哪来?在实行ssoLogin时返回的ticket中,要包含用户的信息(能标识用户唯一性即可,uuid也可以,只是需要在sso的server中记录一下这个uuid和用户的对应关系)
                //webapp1或者webapp2在调用ssoLogout时把ticket传回来即可
    
                if (null == source || Objects.equals("", source)) {
                    String referer = request.getHeader("referer");
                    source = referer.substring(referer.indexOf("source=") + 7);
                }
    
                response.sendRedirect(source + "/logout?domains=" +
                        domains.replace(source + ",", "").replace("," + source, "").replace(source, ""));
            }
    
        }
    }
    

    3、然后对我们的web.xml进行配置

    
    
        
            LoginServlet
            com.jikewenku.sso.servlet.LoginServlet
            
                domains
                http://127.0.0.1:8081,http://127.0.0.1:8082
            
        
        
            LoginServlet
            /login
        
    
        
            LoginServlet
            /ssoLogin
        
    
        
            LoginServlet
            /ssoLogout
        
    
    

    SSO基本功能实现及验证

    接下来我们将完成以下任务:

    1、使用过滤器实现对web应用登录的处理

    2、使用Servlet完成演示中实现的各种跳转及页面请求处理

    3、使用线程实现cookie的添加

    具体实现

    创建一个UserFilter实现Filter接口并覆盖Filter的方法,完成以下编码

    package com.jikewenku.sso.filter;
    
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.Cookie;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.util.Objects;
    
    
    public class UserFilter implements Filter {
    
        private String server;
    
        private String app;
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            server = filterConfig.getInitParameter("server");
            app = filterConfig.getInitParameter("app");
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
            if (Objects.equals("/ssoLogout", ((HttpServletRequest) request).getServletPath())) {
                ((HttpServletResponse) response).sendRedirect(server + "/ssoLogout?source=" + app);
                return;
            }
    
            String ticket = null;
            if (null != ((HttpServletRequest) request).getCookies()) {
                for (Cookie cookie : ((HttpServletRequest) request).getCookies()) {
                    if (Objects.equals(cookie.getName(), "Ticket_Granting_Ticket")) {
                        ticket = cookie.getValue();
                        break;
                    }
                }
            }
    
            if (!Objects.equals(null, ticket)) {
                //判断超时时间
                String[] values = ticket.split(":");
                ticket = request.getParameter("ticket");
                if (Long.valueOf(values[1]) < System.currentTimeMillis()) {//超时
                    if (Objects.equals(null, ticket)) {
                        ((HttpServletResponse) response).sendRedirect(server + "/ssoLogin?source=" + app);
                        return;
                    } else {
                        ticket = ticket + ":" + (System.currentTimeMillis() + 10000);
                        ((HttpServletResponse) response).addCookie(new Cookie("Ticket_Granting_Ticket", ticket));
                        filterChain.doFilter(request, response);
                        return;
                    }
                }
                //应该进行用户校验,如果不是用户或用户非法,需要跳转到登录页面或者不需要登录的页面
                filterChain.doFilter(request, response);
                return;
            }
    
            ticket = request.getParameter("ticket");
            //此处实现的功能是:如果ticket为空,就转到登录页面
            if (!Objects.equals(null, ticket) && !Objects.equals("", ticket.trim())) {
                ticket = ticket + ":" + (System.currentTimeMillis() + 10000);
                ((HttpServletResponse) response).addCookie(new Cookie("Ticket_Granting_Ticket", ticket));
                filterChain.doFilter(request, response);
            } else {
                ((HttpServletResponse) response).sendRedirect(server + "/ssoLogin?source=" + app);
            }
        }
    
        @Override
        public void destroy() {
    
        }
    }
    

    编写web.xml

    
    
        
            UsreFilger
            com.jikewenku.sso.filter.UserFilter
            
                server
                http://127.0.0.1:8080
            
            
                app
                http://127.0.0.1:8081
            
        
       
            UsreFilger
            /*
        
    
    
    

    在WebApp1中的servlet包下创建一个MainServlet继承HTTPServlet,然后完成下面的编码

    package com.jikewenku.sso.servlet;
    
    
    import org.apache.http.HttpEntity;
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClients;
    import org.apache.http.util.EntityUtils;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.Cookie;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.util.Objects;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    /**
     * TODO {file desc}
     */
    public class MainServlet extends HttpServlet {
    
        private ExecutorService service = Executors.newFixedThreadPool(10);
    
        private String servers;
    
        private void syncCookie(String server, String ticket, String method) {
            //submit方法的作用是向线程池提交一个Runable任务用于执行
            service.submit(new Runnable() {
                @Override
                public void run() {
                    //这句话的作用是:创建请求方法的实例,并制定URL。
                    // 如果需要发送POST请求,就创建HTTPPost对象
                    HttpPost httpPost = new HttpPost(server + "/" + method + "?ticket=" + ticket);
                    CloseableHttpClient httpClient = null;
                    CloseableHttpResponse response = null;
                    try {
                        httpClient = HttpClients.createDefault();
                        //将请求发出去了,就会触发另一个应用的Servlet中的
                        // servletPath为/setCookie的代码的执行,
                        // 也就是为另一个应用添加了cookie
                        response = httpClient.execute(httpPost);
                        //此处的entity就是添加cookie的同时存放到response中的ok,
                        //得到该值就说嘛cookie添加成功了
                        HttpEntity entity = response.getEntity();
                        String responseContent = EntityUtils.toString(entity, "UTF-8");
                        System.out.println("=====================" + responseContent);
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        try {
                            if (null != response) {
                                response.close();
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        try {
                            if (null != httpClient) {
                                httpClient.close();
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
        }
    
        @Override
        protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //该方法就是为server参数表示的应用设置cookie也就是一个应用登录后,
            // 会调用setCookie方法为另一个应用设置cookie
            if (Objects.equals("/main", request.getServletPath())) {
                String domains = request.getParameter("domains");
                if (null != domains) {
                    this.servers = domains;
                }
                String ticket = request.getParameter("ticket");
                if (null != domains && null != ticket) {
                    for (String server : domains.split(",")) {
                        if (!Objects.equals(null, server) && !Objects.equals("", server.trim())) {
                            syncCookie(server, ticket, "setCookie");
                        }
                    }
                }
                request.getRequestDispatcher("/WEB-INF/views/main.jsp").forward(request, response);
            } else if (Objects.equals("/setCookie", request.getServletPath())) {
                //也就是说,当一个应用登录成功后调用setCookie()方法,会触发一个请求的执行,就会执行另一个应用的这段else if 后的代码
                String ticket = request.getParameter("ticket");
                response.addCookie(new Cookie("Ticket_Granting_Ticket", ticket));
                response.setCharacterEncoding("UTF-8");
                response.setContentType("application/text; charset=utf-8");
                PrintWriter out = null;
                try {
                    out = response.getWriter();
                    out.write("ok");
                    //ok的值会在另一个应用的setCookie方法中获得,得到ok代表cookie添加成功了
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    if (null != out) {
                        out.close();
                    }
                }
            } else if (Objects.equals("/logout", request.getServletPath())) {
                Cookie cookie = new Cookie("Ticket_Granting_Ticket", null);
                cookie.setMaxAge(0);
                response.addCookie(cookie);
                if (null != servers) {
                    for (String server : servers.split(",")) {
                        if (!Objects.equals(null, server) && !Objects.equals("", server.trim())) {
                            syncCookie(server, "", "removeCookie");
                        }
                    }
                }
                request.getRequestDispatcher("/WEB-INF/views/logout.jsp").forward(request, response);
            } else if (Objects.equals("/removeCookie", request.getServletPath())) {
                Cookie cookie = new Cookie("Ticket_Granting_Ticket", null);
                cookie.setMaxAge(0);
                response.addCookie(cookie);
                response.setCharacterEncoding("UTF-8");
                response.setContentType("application/text; charset=utf-8");
                PrintWriter out = null;
                try {
                    out = response.getWriter();
                    out.write("ok");
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    if (null != out) {
                        out.close();
                    }
                }
            }
        }
    
    }
    

    最终完成web.xml的全部配置

    
    
        
            UsreFilger
            com.jikewenku.sso.filter.UserFilter
            
                server
                http://127.0.0.1:8080
            
            
                app
                http://127.0.0.1:8081
            
        
    
        
            UsreFilger
            /*
        
        
            MainServlet
            com.jikewenku.sso.servlet.MainServlet
        
        
            MainServlet
            /main
        
    
        
            MainServlet
            /setCookie
        
    
        
            MainServlet
            /logout
        
    
        
            MainServlet
            /removeCookie
        
    
        
            MainServlet
            /ssoLogout
        
    
        
            default
            *.jpg
        
        
            default
            *.png
        
        
            default
            *.gif
        
        
            default
            *.ico
        
        
            default
            *.js
        
        
            default
            *.css
        
    
    
    

    然后把WebApp1的代码拷贝到WebApp2中,注意拷贝web.xml的时候注意将端口改成8082.

    然后拷贝我们准备好的main.jsp到views里面

    效果演示

    运行Server、Webapp1和WebApp2,首先在8081端口登录

    然后新开一个标签进入8082端口,此时也登录成功了

    源码下载

    [fanctdl filename='SSO_Demo2.zip' filesize='5.66MB' href='https://pan.baidu.com/s/1rcWYxSASf6GQhuLYGn-uoA' filedown='百度网盘']回复可见密码[/fanctdl]

    密码:[reply]gefd[/reply]

    本站所有文章均由网友分享,仅用于参考学习用,请勿直接转载,如有侵权,请联系网站客服删除相关文章。若由于商用引起版权纠纷,一切责任均由使用者承担
    极客文库 » JSP+Servlet+HttpClient实现单点登录教程(二)

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    极客文库
    程序员的加油站

    3 评论

    Leave a Reply

    Hi, 如果你对这款模板有疑问,可以跟我联系哦!

    联系发布者

    3 评论

    Leave a Reply

    Hi, 如果你对这款模板有疑问,可以跟我联系哦!

    联系发布者
    • 99会员总数(位)
    • 3629资源总数(个)
    • 44本周发布(个)
    • 0 今日发布(个)
    • 105稳定运行(天)

    欢迎加入「极客文库」,成为原创作者从这里开始!

    立即加入 了解更多