需求背景:随着公司的发展,公司内部使用的系统越来越多。但是对于使用系统的员工来说不是个好事情。
     1.每个系统都需要记住对应的账号和密码,很多员工都是每个系统的账户和密码都一样的。
     2.如果同时要使用CRM系统、WMS系统、OA系统,用户需要登录三次,如果10个系统需要登录分别登录十次,非常繁琐。
     3.如果不使用了,还需要分别在三个系统中依次的注销。

需求:
      1.后台用户通过SSO系统实现统一登录,并在SSO系统中点击其他系统并跳转到该系统,无需再次登录。
      2.后台用户未在SSO系统登录时,其他系统无权访问,需统一跳转至SSO系统登录界面。
      3.同步退出机制,即不管在SSO系统中退出,还是在其他系统中退出,实现统一退出,即单点注销。

技术分析:

原理:
相比于单系统登录,sso需要一个独立的认证中心,只有认证中心能接受用户的用户名密码等安全信息,其他系统不提供登录入口,只接受认证中心的间接授权。间接授权通过令牌实现,sso认证中心验证用户的用户名密码没问题,创建授权令牌,在接下来的跳转过程中,授权令牌作为参数发送给各个子系统,子系统拿到令牌,即得到了授权,可以借此创建局部会话,局部会话登录方式与单系统的登录方式相同。

sso认证中心与sso客户端通信方式有多种,这里以简单好用的HttpURLConnection为例,webService、rpc、restful api都可以

会话机制:
1.第一次访问前,浏览器本地没有cookie,服务器也没有对应的session。
2.第一次访问的时候,服务器会创建session对象,每个session对象都会有id,也就是JSESSIONID。
3.服务器会把JSESSIONID通过cookie的方式写到浏览器中。
4.第二次以后的请求,都会在请求服务器的时候,把JSESSIONID带上,通过JSESSIONID就可以找到服务器对应的session对象。
5.不同域名下的系统session对象是不一样的(跨域)。

SSO单点登录系统    JSESSIONID    D7591D0622CB525F165E08C498543457
CRM客户管理系统   JSESSIONID    84C481030AA27C4F2AE2C955CB33EBE5
WMS进销存系统      JSESSIONID    9C757F7AEAD769146317E006DDCA66AB

实现步骤:

修改C:\Windows\System32\drivers\etc\host文件,添加如下配置:
127.0.0.1 www.sso.com
127.0.0.1 www.crm.com
127.0.0.1 www.wms.com

客户端操作(CRM系统、WMS系统、CMS系统...)流程图:

客户端(CRM系统、WMS系统、CMS系统...)项目结构图:

代码:

import java.io.IOException;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(name = "LogOutServlet.java", urlPatterns = "/logOut")
public class LogOutServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doPost(req, resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {req.getSession().invalidate();}
}
import java.io.IOException;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import cn.wolfcode.sso.util.SSOClientUtil;@WebServlet(name = "mainServlet", urlPatterns = "/main")
public class MainServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doPost(req, resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {req.setAttribute("serverLogOutUrl", SSOClientUtil.getServerLogOutUrl());req.getRequestDispatcher("/WEB-INF/views/main.jsp").forward(req, resp);}
}
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;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.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;import org.apache.commons.lang3.StringUtils;import cn.wolfcode.sso.util.HttpUtil;
import cn.wolfcode.sso.util.SSOClientUtil;public class SSOClientFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request;HttpServletResponse resp = (HttpServletResponse) response;String path = req.getRequestURI();System.out.println("crm: "+path);HttpSession session = req.getSession();//1.判断是否有局部的会话Boolean isLogin = (Boolean) session.getAttribute("isLogin");if(isLogin!=null && isLogin){//有局部会话,直接放行.chain.doFilter(request, response);return;}//判断地址栏中是否有携带token参数.String token = req.getParameter("token");if(StringUtils.isNoneBlank(token)){//token信息不为null,说明地址中包含了token,拥有令牌.//判断token信息是否由认证中心产生的.String httpURL = SSOClientUtil.SERVER_URL_PREFIX+"/verify";Map<String,String> params = new HashMap<String,String>();params.put("token", token);params.put("clientUrl", SSOClientUtil.getClientLogOutUrl());params.put("jsessionid", session.getId());try {String isVerify = HttpUtil.sendHttpRequest(httpURL, params);if("true".equals(isVerify)){//如果返回的字符串是true,说明这个token是由统一认证中心产生的.//创建局部的会话.session.setAttribute("isLogin", true);//放行该次的请求chain.doFilter(request, response);return;}} catch (Exception e) {e.printStackTrace();}}//没有局部会话,重定向到统一认证中心,检查是否有其他的系统已经登录过.// http://www.sso.com:8443/checkLogin?redirectUrl=http://www.crm.com:8088SSOClientUtil.redirectToSSOURL(req, resp);}@Overridepublic void destroy() {}
}
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.Map.Entry;import org.springframework.util.StreamUtils;public class HttpUtil {/*** 模拟浏览器的请求* @param httpURL 发送请求的地址* @param params  请求参数* @return* @throws Exception*/public static String sendHttpRequest(String httpURL,Map<String,String> params) throws Exception{//建立URL连接对象URL url = new URL(httpURL);//创建连接HttpURLConnection conn = (HttpURLConnection) url.openConnection();//设置请求的方式(需要是大写的)conn.setRequestMethod("POST");//设置需要输出conn.setDoOutput(true);//判断是否有参数.if(params!=null&&params.size()>0){StringBuilder sb = new StringBuilder();for(Entry<String,String> entry:params.entrySet()){sb.append("&").append(entry.getKey()).append("=").append(entry.getValue());}//sb.substring(1)去除最前面的&conn.getOutputStream().write(sb.substring(1).toString().getBytes("utf-8"));}//发送请求到服务器conn.connect();//获取远程响应的内容.String responseContent = StreamUtils.copyToString(conn.getInputStream(),Charset.forName("utf-8"));conn.disconnect();return responseContent;}/*** 模拟浏览器的请求* @param httpURL 发送请求的地址* @param jesssionId 会话Id* @return* @throws Exception*/public static void sendHttpRequest(String httpURL,String jesssionId) throws Exception{//建立URL连接对象URL url = new URL(httpURL);//创建连接HttpURLConnection conn = (HttpURLConnection) url.openConnection();//设置请求的方式(需要是大写的)conn.setRequestMethod("POST");//设置需要输出conn.setDoOutput(true);conn.addRequestProperty("Cookie","JSESSIONID="+jesssionId);//发送请求到服务器conn.connect();conn.getInputStream();conn.disconnect();}
}
import java.io.IOException;
import java.util.Properties;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class SSOClientUtil {private static Properties ssoProperties = new Properties();public static String SERVER_URL_PREFIX;//统一认证中心地址:http://www.sso.com:8443,在sso.properties配置public static String CLIENT_HOST_URL;//当前客户端地址:http://www.crm.com:8088,在sso.properties配置static{try {ssoProperties.load(SSOClientUtil.class.getClassLoader().getResourceAsStream("sso.properties"));} catch (IOException e) {e.printStackTrace();}SERVER_URL_PREFIX = ssoProperties.getProperty("server-url-prefix");CLIENT_HOST_URL = ssoProperties.getProperty("client-host-url");}/*** 当客户端请求被拦截,跳往统一认证中心,需要带redirectUrl的参数,统一认证中心登录后回调的地址* 通过Request获取这次请求的地址 http://www.crm.com:8088/main* * @param request* @return*/public static String getRedirectUrl(HttpServletRequest request){//获取请求URLreturn CLIENT_HOST_URL+request.getServletPath();}/*** 根据request获取跳转到统一认证中心的地址 http://www.sso.com:8443//checkLogin?redirectUrl=http://www.crm.com:8088/main* 通过Response跳转到指定的地址* @param request* @param response* @throws IOException*/public static void redirectToSSOURL(HttpServletRequest request,HttpServletResponse response) throws IOException {String redirectUrl = getRedirectUrl(request);StringBuilder url = new StringBuilder(50).append(SERVER_URL_PREFIX).append("/checkLogin?redirectUrl=").append(redirectUrl);response.sendRedirect(url.toString());}/*** 获取客户端的完整登出地址 http://www.crm.com:8088/logOut* @return*/public static String getClientLogOutUrl(){return CLIENT_HOST_URL+"/logOut";}/*** 获取认证中心的登出地址 http://www.sso.com:8443/logOut* @return*/public static String getServerLogOutUrl(){return SERVER_URL_PREFIX+"/logOut";}
}

sso.properties

server-url-prefix=http://www.sso.com:8443
client-host-url=http://www.crm.com:8088

main.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>客户关系管理系统</title>
</head>
<body>
<h1>这是客户管理系统的首页</h1>
<div style="text-align: right;width: 25%;"><a href="${serverLogOutUrl}">退出系统</a>
</div>
</body>
</html>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"><filter><filter-name>SSOClientFilter</filter-name><filter-class>cn.wolfcode.sso.filter.SSOClientFilter</filter-class></filter><filter-mapping><filter-name>SSOClientFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>
</web-app>

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>cn.wolfcode.sso</groupId><artifactId>client-crm</artifactId><version>1.0.0</version><packaging>war</packaging><dependencies><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.0.1</version><scope>provided</scope></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.2</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>4.2.3.RELEASE</version></dependency></dependencies><build><finalName>client-crm</finalName><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>1.7</source><target>1.7</target></configuration></plugin></plugins></build>
</project>

服务端(SSO系统)操作流程图:

/checkLogin
1.检测客户端在服务端是否已经登录了
    1.1获取session中的token.
    1.2如果token不为空,说明服务端已经登录过了,此时重定向到客户端的地址,并把token带上
    1.3如果token为空,跳转到统一认证中心的的登录页面,并把redirectUrl放入到request域中.

/user_login
2.统一认证中心的登录方法
    2.1判断用户提交的账号密码是否正确.
    2.2如果正确
        2.2.1创建token(可以使用UUID,保证唯一就可以)
        2.2.2把token放入到session中.
        2.2.3这个token要知道有哪些客户端登陆了,创建Map<String,List<String[]> clientMap;(为单点注销做准备)
                  SSOUtil.clientMap.put(token,new ArrayList());(把这些数据放入到数据库中也是可以的,我们就做比较简单的,模拟一下.)
        2.2.4转发到redirectUrl地址,把token带上.
    2.3如果错误
        转发到login.jsp,还需要把redirectUrl参数放入到request域中.
/verify
3.统一认证中心认证token方法
    3.1如果SSOUtil.clientMap.get(token)有数据clientList,说明token是有效的.
        3.1.1clientList把客户端传入的客户端登出地址(clientLogOutUrl)和会话ID(jsessionid)保存到集合中.
        3.1.2返回true字符串.
    3.1如果SSOUtil.clientMap.get(token)为null,说明token是无效的,返回false字符串.

项目结构图:

代码:

import cn.wolfcode.sso.util.MockDatabaseUtil;
import cn.wolfcode.sso.vo.ClientInfoVo;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;/*** Created by yz*/
@Controller
public class SSOServerController {@RequestMapping("/")public String index(){return "index";}@RequestMapping("/login")public String login(){return "login";}@RequestMapping("/test")public String test(){return "test";}@RequestMapping("/checkLogin")public String checkLogin(String redirectUrl, HttpSession session,Model model){//1.判断是否有全局的会话String token = (String) session.getAttribute("token");if(StringUtils.isEmpty(token)){//表示没有全局会话//跳转到统一认证中心的登陆页面.model.addAttribute("redirectUrl",redirectUrl);return "login";}else{//有全局会话//取出令牌信息,重定向到redirectUrl,把令牌带上  http://www.wms.com:8089/main?tokenmodel.addAttribute("token",token);return "redirect:"+redirectUrl;}}/*** 登陆功能*/@RequestMapping("/user_login")public String login(String username,String password,String redirectUrl,HttpSession session,Model model){if("admin".equals(username)&&"123456".equals(password)){//账号密码匹配//1.创建令牌信息String token = UUID.randomUUID().toString();//2.创建全局的会话,把令牌信息放入会话中.session.setAttribute("token",token);//3.需要把令牌信息放到数据库中.MockDatabaseUtil.T_TOKEN.add(token);if(StringUtils.isEmpty(redirectUrl)){return "redirect:/";}//4.重定向到redirectUrl,把令牌信息带上.  http://www.crm.com:8088/main?token=model.addAttribute("token",token);return "redirect:"+redirectUrl;}//如果账号密码有误,重新回到登录页面,还需要把redirectUrl放入request域中.if(!StringUtils.isEmpty(redirectUrl)){model.addAttribute("redirectUrl",redirectUrl);}return "redirect:login";}/*** 校验token是否由统一认证中心产生的**/@RequestMapping("/verify")@ResponseBodypublic String verifyToken(String token,String clientUrl,String jsessionid){if(MockDatabaseUtil.T_TOKEN.contains(token)){//把客户端的登出地址记录List<ClientInfoVo> clientInfoList = MockDatabaseUtil.T_CLIENT_INFO.get(token);if(clientInfoList==null){clientInfoList = new ArrayList<ClientInfoVo>();MockDatabaseUtil.T_CLIENT_INFO.put(token,clientInfoList);}ClientInfoVo vo = new ClientInfoVo();vo.setClientUrl(clientUrl);vo.setJsessionid(jsessionid);clientInfoList.add(vo);//说明令牌有效,返回truereturn "true";}return "false";}@RequestMapping("/logOut")public String logOut(HttpSession session){//销毁全局会话session.invalidate();return "redirect:login";}
}
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;/*** @description: 登录拦截器* @author: yz* @create: 2018/11/16 11:38*/
public class LoginFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {HttpServletRequest req = (HttpServletRequest) request;HttpServletResponse resp = (HttpServletResponse) response;// 如果是登录有关操作的,不拦截String path = req.getRequestURI();// 1. session还有效HttpSession session = req.getSession();String token = (String) session.getAttribute("token");if(token != null){// 放行chain.doFilter(request,response);return;}if (path.contains("login") || path.endsWith(".css") || path.endsWith(".js")){// 放行chain.doFilter(request,response);return;}else{System.out.println("path:"+path);if(path.endsWith("verify")){// 放行chain.doFilter(request,response);return;}else {resp.sendRedirect("login");}}}@Overridepublic void destroy() {}
}
import cn.wolfcode.sso.util.HttpUtil;
import cn.wolfcode.sso.util.MockDatabaseUtil;
import cn.wolfcode.sso.vo.ClientInfoVo;import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import java.util.List;/*** 监听session,用于退出所有客户端*/
public class MySessionListener implements HttpSessionListener {@Overridepublic void sessionCreated(HttpSessionEvent se) {}@Overridepublic void sessionDestroyed(HttpSessionEvent se) {HttpSession session = se.getSession();String token = (String) session.getAttribute("token");//删除t_token表中的数据MockDatabaseUtil.T_TOKEN.remove(token);List<ClientInfoVo> clientInfoVoList = MockDatabaseUtil.T_CLIENT_INFO.remove(token);try{if(clientInfoVoList !=null){for(ClientInfoVo vo:clientInfoVoList){//获取出注册的子系统,依次调用子系统的登出的方法HttpUtil.sendHttpRequest(vo.getClientUrl(),vo.getJsessionid());}}}catch(Exception e){e.printStackTrace();}}
}
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.Map.Entry;import org.springframework.util.StreamUtils;public class HttpUtil {/*** 模拟浏览器的请求* @param httpURL 发送请求的地址* @param params  请求参数* @return* @throws Exception*/public static String sendHttpRequest(String httpURL,Map<String,String> params) throws Exception{//建立URL连接对象URL url = new URL(httpURL);//创建连接HttpURLConnection conn = (HttpURLConnection) url.openConnection();//设置请求的方式(需要是大写的)conn.setRequestMethod("POST");//设置需要输出conn.setDoOutput(true);//判断是否有参数.if(params!=null&&params.size()>0){StringBuilder sb = new StringBuilder();for(Entry<String,String> entry:params.entrySet()){sb.append("&").append(entry.getKey()).append("=").append(entry.getValue());}//sb.substring(1)去除最前面的&conn.getOutputStream().write(sb.substring(1).toString().getBytes("utf-8"));}//发送请求到服务器conn.connect();//获取远程响应的内容.String responseContent = StreamUtils.copyToString(conn.getInputStream(),Charset.forName("utf-8"));conn.disconnect();return responseContent;}/*** 模拟浏览器的请求* @param httpURL 发送请求的地址* @param jesssionId 会话Id* @return* @throws Exception*/public static void sendHttpRequest(String httpURL,String jesssionId) throws Exception{//建立URL连接对象URL url = new URL(httpURL);//创建连接HttpURLConnection conn = (HttpURLConnection) url.openConnection();//设置请求的方式(需要是大写的)conn.setRequestMethod("POST");//设置需要输出conn.setDoOutput(true);conn.addRequestProperty("Cookie","JSESSIONID="+jesssionId);//发送请求到服务器conn.connect();conn.getInputStream();conn.disconnect();}
}
import cn.wolfcode.sso.vo.ClientInfoVo;import java.util.*;/*** 模拟数据库,保存子系统的session对象信息*/
public class MockDatabaseUtil {public static Set<String> T_TOKEN = new HashSet<String>();public static Map<String,List<ClientInfoVo>> T_CLIENT_INFO =new HashMap<String,List<ClientInfoVo>>();
}
/*** 客户端信息*/
public class ClientInfoVo {private String clientUrl;private String jsessionid;public String getClientUrl() {return clientUrl;}public void setClientUrl(String clientUrl) {this.clientUrl = clientUrl;}public String getJsessionid() {return jsessionid;}public void setJsessionid(String jsessionid) {this.jsessionid = jsessionid;}@Overridepublic String toString() {return "ClientInfoVo{" +"clientUrl='" + clientUrl + '\'' +", jsessionid='" + jsessionid + '\'' +'}';}
}

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"><!--开启注解扫描--><context:component-scan base-package="cn.wolfcode.sso"/><!--mvc注解驱动支持--><mvc:annotation-driven/><!--静态资源处理--><mvc:default-servlet-handler/><!--视图解析器--><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/views/"/><property name="suffix" value=".jsp"/></bean>
</beans>

index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>sso单点登录系统</title>
</head>
<body>
<h1>这是sso单点登录的首页</h1>
<div style="text-align:center;"><a href="http://www.crm.com:8088/main" target="_blank">crm系统</a>&emsp; &emsp; &emsp; &emsp; <a href="http://www.wms.com:8089/main" target="_blank">wms系统</a>&emsp; &emsp; &emsp; &emsp;<a href="/logOut">退出系统</a>
</div>
</body>
</html>

login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>统一认证中心</title><link rel="stylesheet" type="text/css" href="/static/css/style.css" /><script type="text/javascript" src="/static/js/jquery-latest.min.js"></script><script type="text/javascript" src="/static/js/placeholder.js"></script>
</head>
<body>
${errorMsg}
<form id="slick-login" method="post" action="/user_login"><input type="hidden" name="redirectUrl" value="${redirectUrl}"><label>username</label><input type="text" name="username" class="placeholder" placeholder="账号"><label>password</label><input type="password" name="password" class="placeholder" placeholder="密码"><input type="submit" value="登录">
</form>
</body>
</html>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://java.sun.com/xml/ns/javaee"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"id="WebApp_ID" version="3.0"><display-name>Archetype Created Web Application</display-name><filter><filter-name>LoginFilter</filter-name><filter-class>cn.wolfcode.sso.filter.LoginFilter</filter-class></filter><filter-mapping><filter-name>LoginFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping><servlet><servlet-name>SpringMVC</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>SpringMVC</servlet-name><url-pattern>/</url-pattern></servlet-mapping><listener><listener-class>cn.wolfcode.sso.listener.MySessionListener</listener-class></listener></web-app>

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><groupId>cn.wolfcode.sso</groupId><artifactId>server</artifactId><packaging>war</packaging><version>1.0.0</version><name>server Maven Webapp</name><url>http://maven.apache.org</url><dependencies><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.0.1</version><scope>provided</scope></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId><version>1.1.2</version></dependency><dependency><groupId>taglibs</groupId><artifactId>standard</artifactId><version>1.1.2</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>4.2.3.RELEASE</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.16.6</version></dependency></dependencies><build><finalName>server</finalName><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>1.7</source><target>1.7</target></configuration></plugin></plugins></build>
</project>

单点退出操作:

单点退出流程:用户在SSO系统登录后创建token,保存token到数据库t_token表中,当子系统登录时,将该token的子系统信息:退出url和jsessionid信息保存到t_client_info表,一对多关系。当用户点击退出时,调用SSO系统/logOut方法,销毁sesseion,并在web.xml中注册session监听器,当有销毁操作时,调出t_client_info表对象信息,并依次调用子系统的/logOut方法,根据jsessionid销毁子系统中session对象信息,从而实现全部退出。

整体效果图:

输入账号密码登录后:


 在SSO系统中分别进入CRM系统、WMS系统

三个系统中不管哪个系统点击退出系统,全部退出,并再次跳转到SSO系统登录界面。根据不同单点登录需求,修改代码,这里针对后台所有系统统一登录管理。

java单点登录需求分析与代码实现相关推荐

  1. php java 单点登录_用cas来实现php的单点登陆

    最近项目中需要做单点登录,客户端包含Java.ruby和PHP,java有几个应用程序,php是discuz+supesite+ucenter,配置步骤如下: 1.cas服务端:下载地址:http:/ ...

  2. Java单点登录在校园身份管理系统中的实现

    java单点登录在校园身份管理系统中的实现 摘要: 一个学校或企业的内部有很多信息系统,用户登录这些系统时需要进行身份认证.传统的认证机制是基于用户名和密码的,每一个系统都建立有自己的用户信息数据库, ...

  3. cas java单点登录_java单点登录系统CAS的简单使用

    http://blog.csdn.net/yunye114105/article/details/7997041 参考: http://blog.csdn.net/diyagea/article/de ...

  4. Java单点登录技术选型与对比 kisso, sa-token

    背景介绍 单点登录SSO(Single Sign On),就是在多系统环境下,用户在其中一个系统登录后,就不用在其它系统再登录了. 早期我们的web系统都是单体应用,所有功能都写到一个war包中,用户 ...

  5. java单点登录跨域_深入浅出让你理解跨域与SSO单点登录原理与技术

    原标题:深入浅出让你理解跨域与SSO单点登录原理与技术 一:SSO体系结构 SSO SSO英文全称Single Sign On,单点登录.SSO是在多个应用系统中,用户只需要登录一次就可以访问所有相互 ...

  6. php java 单点登录_php实现多站点共用session实现单点登录的方法详解

    本文实例讲述了php实现多站点共用session实现单点登录的方法.分享给大家供大家参考,具体如下: 最近闲来无事,总结整理下单点登录的问题. 单点登录的基本原理为:客户端共享sesionid,服务器 ...

  7. java单点登录统一认证,JEECG 集成KiSSO单点登录实现统一身份认证

    JEECG 集成KiSSO单点登录实现统一身份认证 JEECG 如何为其他第三方系统实现统一身份认证服务,实现单点登录? 第三方系统如何对接呢? 今天为大家揭开这层面纱,让大家了解实质,使用它更快速的 ...

  8. java单点登录强制下线_实现单点登录并强制对方下线

    前些天做了一个网站,客户的要求是实现单点登录,并如果有人在用这个号码登录就强制第一个人下线.自己以前看到过这个例子,是将用户登录的信息存储在application之中,登录的时候判断是否由此信息,来实 ...

  9. java单点登录token_单点登录(token,JWT)

    一.什么事单点登录? 答:单点登录SSO(Single Sign On)说得简单点就是在一个多系统共存的环境下,用户在一处登录后,就不用在其他系统中登录,也就是用户的一次登录能得到其他所有系统的信任. ...

  10. java php 单点登陆,cas实现单点登录,登出(java跟php客户端)(转)

    cas实现单点登录,登出(java跟php客户端)(转)cas实现单点登录,登出(java和php客户端) (转) 最近项目中需要做单点登录,客户端包含java和php,java有几个应用程序,php ...

最新文章

  1. Service 层和 Dao 层有必要为每个类都加上接口吗?
  2. Docker(二):Dockerfile 使用介绍
  3. 华为9.0系统机器一键激活xposed框架的流程
  4. 107条javascript常用小技巧
  5. python函数应用_Python 函数及其应用
  6. 产品问答 | 作为项目负责人,怎么提升成员工作斗志?
  7. 每天一道LeetCode-----将数值数组按一定顺序拼接,使得拼接的结果最大
  8. vscode安装python插件失败_vscode插件安装失败的解决方案
  9. 俩台电脑怎么设置同一局域网_方法 | 把手机上的照片传到电脑上
  10. python tkinter实例_Python tkinter模版代码实例
  11. python入门先学什么-Python入门学习 DAY 01 计算机基础
  12. c语言 树的遍历,c语言构造树及树的三种遍历
  13. Jmeter安装及简单使用
  14. 360安全卫士清理C盘
  15. python土味情话_GitHub - MMstarry/itchat: 微信机器人 土味情话
  16. 苹果6访问限制密码4位_苹果ios签名:AppleID为什么开启双重认证那么重要
  17. 初识微信小程序 图片与声音
  18. 电脑PHP动画制作画板,HTML_html5教程制作简单画板代码分享,HTML5制作简单画板 复制代码代 - phpStudy...
  19. 【DB笔试面试696】在Oracle中,什么OSWatcher工具?
  20. 跨境电商政策利好,商家如何破局“三封”难题

热门文章

  1. 手把手教你SPSS进行ROC曲线分析
  2. 56个民族HTML代码
  3. PyTorch 单机多GPU 训练方法与原理整理
  4. MapGIS K9三维TDE平台实现动态光标效果
  5. 程序设计基础II学习笔记
  6. python读取文本后如何加拼音_[编程心得]用Python给汉字加上带音调的拼音
  7. Adbyby无法更新规则的解决方案
  8. java修改yml文件
  9. SpringBoot 整合 kaptcha + redis 实现 图形验证码登录
  10. 2023年前实现大型工业企业5G应用渗透率超35%!模组企业如何保驾护航?