官方介绍:单点登录,简称为 SSO,是目前比较流行的企业业务整合的解决方案之一。 SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。是指在多系统应用群中登录一个系统,便可在其他所有系统中得到授权而无需再次登录,包括单点登录与单点注销两部分。

一,单点登录实现的原理

以单个客户端访问单个服务端来讲,以下图为例!

1.1 会话机制

1.浏览器在第一次访问Tomcat服务器的时候,Tomcat服务器会在服务端创建session对象,并存储到map中,key是session的id,value是session对象本身。

2.在响应的时候会把session的id通过cookie的方式写到客户端浏览器中。

3.浏览器会在本地的目录中把session的id写入到本地的cookie中。

4.在后续的请求中,都会读取本地的cookie中的内容,并在请求的时候带上对应的cookie。

有了会话机制,登录状态就好明白了,我们假设浏览器第一次请求服务器需要输入用户名与密码验证身份,服务器拿到用户名密码去数据库比对,正确的话说明当前持有这个会话的用户是合法用户,应该将这个会话标记为“已授权”或者“已登录”等等之类的状态,既然是会话的状态,自然要保存在会话对象中,Tomcat在会话对象中设置登录状态如下:

HttpSession session = request.getSession();
session.setAttribute("isLogin", true);

用户再次访问时,tomcat在会话对象中查看登录状态:

HttpSession session = request.getSession();
session.getAttribute("isLogin");

实现了登录状态的浏览器请求服务器模型如下图描述

每次请求受保护资源时都会检查会话对象中的登录状态,只有isLogin=true的会话才能访问,登录机制因此而实现。

2、多系统的复杂性

随着公司的发展,公司内部使用的系统越来越多,但是对于使用系统的员工来说不是个好事情。

1.每个系统都需要记住对应的账号和密码,很多员工都是每个系统的账户和密码都一样的。

2.如果同时要使用CRM系统,WMS系统,OA系统,用户需要登录三次。

3.如果不使用了,还需要分别在三个系统中依次的注销。
有没有这样的功能:我只需要登录一次,公司里面所有的系统都可以使用,只需要注销一次,所有的系统都退出登录了,

如果能实现这样的功能就非常好了!

单系统登录解决方案的核心是cookie,cookie携带会话id在浏览器与服务器之间维护会话状态。但cookie是有限制的,这个限制就是cookie的域(通常对应网站的域名),浏览器发送http请求时会自动携带与该域匹配的cookie,而不是所有cookie。什么意思呢?就是每个域名下面都有属于自己的cookie域,如果是多个系统,那么就会有多个域名,而这些下面的cookie不能实现共享,只能各玩各的。

既然这样,为什么不将web应用群中所有子系统的域名统一在一个顶级域名下,例如*.baidu.com,然后将它们的cookie域设置为baidu.com,这种做法理论上是可以的,甚至早期很多多系统登录就采用这种同域名共享cookie的方式。

然而,可行并不代表好,共享cookie的方式存在众多局限。首先,应用群域名得统一;其次,应用群各系统使用的技术(至少是web服务器)要相同,不然cookie的key值(tomcat为JSESSIONID)不同,无法维持会话,共享cookie的方式是无法实现跨语言技术平台登录的,比如java、php、.net系统之间;第三,cookie本身不安全。

3、单点登录的实现过程

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

二、Http间的通信

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

1,HttpUrlConnection的简单实用

在JDK的java.net包中已经提供了访问HTTP协议的基本功能的类:HttpURLConnection。

HttpURLConnection是Java的标准类,它继承自URLConnection,可用于向指定网站发送GET请求、POST请求。

具体代码在下面的代码实现步骤再详细讲解!、

三、单点登录的实现步骤(语言描述)

1,客户端操作

1.拦截客户端的请求判断是否有局部的session
2.1如果有局部的session,放行请求
2.2如果没有局部session
   2.2.1请求中有携带token参数
    
             2.2.1.1如果有,使用HttpURLConnection发送请求校验token是否有效
    
                           2.2.1.1.1如果token有效,建立局部的session

2.2.1.1.2如果token无效,重定向到统一认证中心页面进行登陆

2.2.1.2如果没有,重定向到统一认证中心页面进行登陆

2.2.2请求中没有携带token参数,重定向到统一认证中心页面进行登陆

2、服务端操作

1.检测客户端在服务端是否已经登录了(checkLogin方法)
1.1获取session中的token
1.2如果token不为空,说明服务端已经登录过了,此时重定向到客户端的地址,并把token带上

1.3如果token为空,跳转到统一认证中心的的登录页面,并把redirectUrl放入到request域中
2.统一认证中心的登录方法(login方法)
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域中
3.统一认证中心认证token方法(verify方法),返回值为String,贴@ResponseBody
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字符串

四,单点注销的实现步骤(语言描述)

1、客户端操作

在登陆的按钮链接写上统一认证中心的登出方法即可.

<a href="http://www.sso.com/logOut">退出</a>

2、服务端操作

1,编写logOut方法,调用session.invalidate()
2,创建session的监听器,在session的监听器的销毁方法写如下逻辑2.1,获取session中的token2.2,根据token在SSOUtil.clientMap获取所有客户端的登出地址和会话id2.3,通过HttpUtil选项调用客户端的登出方法3,将session监听器注册到web.xml中

五、手写单点登录的实现

1、在hosts文件中添加配置

127.0.0.1 www.zhongxin.com
127.0.0.1 www.jiudian.com
127.0.0.1 www.wuliu.com

这样做的目的是测试的时候可以明确的分辨出来每个系统。

2、创建三个web的springboot项目

sso_client1 酒店管理系统
sso_client2物流管理系统
sso_server统一认证中心
因为是在本机上测试,所以给酒店管理系统设置端口为8081,物流管理系统端口为8082,而统一认证中心的端口为8080。

这样的话,访问每个系统的路径就是

酒店管理系统 http://www.jiudian.com:8081/main
物流管理系统 http://www.wuliu.com:8082/main
统一认证中心 http://www.zhongxin.com:8080/checkLogin
(1)子系统的代码实现

首先写第一个子系统(酒店管理系统),其实子系统的功能代码都是一样的,唯一不一样的无非就是改一下端口这些最主要的区别,一个子系统写好之后复制一份就是另一个子系统了。

配置sso.properties文件

这个配置文件的作用其实就是指定了统一认证中心的地址和本系统地址,为了后续到这个文件中直接取地址,而不用手写了。

server-url-prefix=http://www.zhongxin.com:8080
client-host-url=http://www.jiudian.com:8081

添加SSOClientUtil工具类

这个工具类就是去sso.properties配置文件中拿地址,并且封装了跳转到统一认证中心的方法。

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.jiudian.com:8081/* * @param request* @return*/public static String getRedirectUrl(HttpServletRequest request){//获取请求URLreturn CLIENT_HOST_URL+request.getServletPath();}/*** 根据request获取跳转到统一认证中心的地址 http://www.zhongxin.com:8080/checkLogin?redirectUrl=http://www.jiudian.com:8081/* 通过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.jiudian.com:8081/logOut* @return*/public static String getClientLogOutUrl(){return CLIENT_HOST_URL+"/logOut";}/*** 获取认证中心的登出地址 http://www.zhongxin.com:8080/logOut* @return*/public static String getServerLogOutUrl(){return SERVER_URL_PREFIX+"/logOut";}
}

添加HttpUtil工具类

这个工具类的作用主要是帮我们封装了发起浏览器的请求,跨域访问,参数使用Map集合进行传递。

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();}
}

准备html页面和controller跳转方法

这一切都是在配置了thymeleaf模板引擎的前提下进行的。

就是在浏览器发起请求http://www.jiudian.com:8081/main可以跳到欢迎页面

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
欢迎进入一天一次酒店的管理系统
<a href="http://www.zhongxin.com:8080/logout">退出</a>
</body>
</html>
@Controller
public class TestController {@RequestMapping("/main")public String show(){return "index";}
}

配置过滤器

当然,在没有登录的时候是不可以直接访问欢迎页面的,这里说明一下:登录是在统一认证中心进行的!所以需要配置一个过滤器,在发起请求之后会先进到过滤器中。

在过滤器中一共做下面几件事情:

判断是否有局部会话,如果有,则放行,如果没有,重定向到统一认证中心,检查是否有其他的系统已经登录过。
判断地址栏中是否携带了token参数(这是在统一认证中心登录之后重定向过来的请求,会带上token),如果有token,那么向统一认证中心发起请求来判断该token是否由统一认证中心产生的,如果是,则放行,如果不是,重定向到统一认证中心去登录。
说明:

通过实现Filter接口,创建一个过滤器类,通过@WebFilter注解,注册过滤器。
urlPatterns属性代表需要被过滤的请求地址。filterName属性代表过滤器名称;
在SpringBoot应用启动类中,添加@ServletComponentScan注解,表示项目启动自动扫描Servlet组件。Filter属于Servlet组件
引起注意的一点:重定向到统一认证中心的路径是http://www.zhongxin.com:8080/checkLogin?redirectUrl=http://www.jiudian.com:8081/main这种格式的,就是前面是http请求,后面加上了redirectUrl参数,为本子系统的访问路径,因为把这个传到认证中心之后,在认证中心登录之后还要拿到这个参数(子系统访问路径)进行转发回来。

看一下底层代码:

 它是将认证中心的路径和子系统的路径做了一个拼接,然后response进行了重定向。

过滤器代码

/*** 通过实现Filter接口,创建一个过滤器类* 通过@WebFilter注解,注册过滤器。urlPatterns属性代表需要被过滤的请求地址。filterName属性代表过滤器名称* 在SpringBoot应用启动类中,添加@ServletComponentScan注解,表示项目启动自动扫描Servlet组件。Filter属于Servlet组件*/
@Component  //加入tomcat容器
@WebFilter(urlPatterns = "/*",filterName = "ssoFilter")
public class SSOClientFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {System.err.println("############进入了过滤器#############");HttpServletRequest req = (HttpServletRequest) request;HttpServletResponse res= (HttpServletResponse) response;HttpSession session = req.getSession();//1,判断是否有局部的会话Boolean isLogin= (Boolean) session.getAttribute("isLogin");if(isLogin!=null && isLogin){//有局部会话,直接放行chain.doFilter(request,response);return;}//判断地址栏中是否携带了token参数(这是在统一认证中心登录之后重定向过来的请求,会带上token)String token=req.getParameter("token");if(token!=null || token !=""){//token信息不为null,拥有令牌//判断token信息是否由认证中心产生的//这里使用写好的工具类发送http请求  SSOClientUtil.SERVER_URL_PREFIX是统一认证中心的IPString httpUrl=SSOClientUtil.SERVER_URL_PREFIX+"/verify";//参数Map<String,String> params=new HashMap<String, String>();params.put("token",token);//这里放入clientUrl和jsessionId这两个参数是为了单点注销做准备params.put("clientUrl",SSOClientUtil.getClientLogOutUrl());params.put("jsessionId",session.getId());try {//发送请求,server端(统一认证中心)会返回一个字符串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();}}//2,没有局部会话,重定向到统一认证中心,检查是否有其他的系统已经登录过//http://www.zhongxin.com:8080/checkLogin?redirectUrl=http://www.jiudian.com:8081SSOClientUtil.redirectToSSOURL(req,res);}@Overridepublic void destroy() {}
}

到这里子系统的代码已经完成了,接下来开始写统一认证中心。

(2)统一认证中心的代码实现

首先项目要配置好thymeleaf模板引擎,这都不用说了吧?

然后先准备一个登录页面。表单项redirectUrl是隐藏的,是子系统的路径,是表单提交的一个参数,因为在登录方法中进行验证,如果账号密码成功之后,还要拿到这个路径进行重定向回来。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>登录</title><script src="js/jquery.1.12.4.min.js"></script>
</head>
<body>
<h1>请登录</h1>
<!--<span id="span" th:text="${redirectUrl}"></span>-->
<form id="form" action="/login" method="post"><input type="hidden" th:value="${redirectUrl}" name="redirectUrl">账号:<input type="text" name="username"><br>密码:<input type="password" name="password"><br><input type="submit" value="登录">
</form>
</body>
</html>

模拟数据库

这里没有连接数据库,只是使用集合来存储数据来模拟一下。

其实需要两张表,一张是存放token令牌的表T_TOKEN,另一张是存放统计注册过的子系统信息的表T_CLIENT_INFO(token为id,其他字段为clientUrl(子系统访问路径),jsessionid(session的id),这里使用集合表示了)

先建一个实体类,装载子系统的信息。

public class ClientInfo {private String clientUrl;private String jsessionid;}

DataBaseUtil类,连个集合(代表两张表)

public class DataBaseUtil {//创建一个存放token令牌信息的集合public static Set<String> T_TOKEN=new HashSet<String>();//创建一个统计注册过的子系统信息的集合public static Map<String, List<ClientInfo>> T_CLIENT_INFO=new HashMap<String, List<ClientInfo>>();
}

添加HttpUtil工具类

因为如果登录成功之后要重定向到子系统,所以需要这个工具类来进行跨域请求。

这个类上面已经给过了,略过。

在controller进行处理(中心内容)

在这个controller中要做下面几件事:

检查是否登录,判断是否有全局会话,如果没有,跳转到统一认证中心的登录页面,也就是本系统的登录页面,如果有,
1.取出令牌信息,重定向到子系统,把令牌带上。

2. 登录功能,检查账号密码是否匹配, 如果匹配,创建令牌信息,创建全局会话,把令牌信息放到会话中,重定向`redirectUrl`子系统,并把令牌信息带上;如果不匹配,则重新回到登录页面,还需要把`redirectUrl`放到`request`域中。
    3. 校验`token`是否由统一认证中心产生的,如果是,则返回`true`字符串,并记录客户端的登出地址,记录登出地址是为了单点注销做准备的。
    4. 单点注销。

@Controller
public class TestController {@RequestMapping("/checkLogin")public String show(String redirectUrl, HttpSession session, Model model){//1,判断是否有全局的会话String token= (String) session.getAttribute("token");if(token==null || token==""){//表示没有全局会话//跳转到统一认证中心的登录页面,也就是本系统的登录页面model.addAttribute("redirectUrl",redirectUrl);return "login";}else{//有全局会话//取出令牌信息,重定向到redirectUrl,把令牌带上return "redirect:"+redirectUrl+"?token="+token;}}/*** 登录功能*/@RequestMapping("/login")public String login(String username,String password,String redirectUrl,HttpSession session,Model model){if("admin".equals(username)&&"123".equals(password)){//账号密码匹配//1,创建令牌信息String token= UUID.randomUUID().toString();//2,创建全局会话,把令牌信息放到会话中session.setAttribute("token",token);//3,需要把令牌放到数据库中,这里不连数据库,创建list模拟一下DataBaseUtil.T_TOKEN.add(token);//4,重定向redirectUrl,并把令牌信息带上 http://www.jiudian.com:8081/main?token=//参数可存放到model,可以直接重定向带过去return "redirect:"+redirectUrl+"?token="+token;}else{//账号密码错误,重新回到登录页面,还需要把redirectUrl放到request域中model.addAttribute("redirectUrl",redirectUrl);return "login";}}/*** 校验token是否由统一认证中心产生的*/@RequestMapping("/verify")@ResponseBodypublic String verify(String token,String clientUrl,String jsessionId){if(DataBaseUtil.T_TOKEN.contains(token)){//记录客户端的登出地址List<ClientInfo> clientInfoList = DataBaseUtil.T_CLIENT_INFO.get("token");if(clientInfoList==null){clientInfoList=new ArrayList<ClientInfo>();DataBaseUtil.T_CLIENT_INFO.put(token,clientInfoList);}ClientInfo clientInfo=new ClientInfo();clientInfo.setClientUrl(clientUrl);clientInfo.setJsessionid(jsessionId);clientInfoList.add(clientInfo);//说明令牌有效,返回truereturn "true";}return "false";}/*** 单点注销*/@RequestMapping("logout")@ResponseBodypublic String logout(HttpSession session){/*** 销毁全局会话* session.invalidate()方法会执行session监听器的销毁方法(什么是session监听器?)*/session.invalidate();return "退出成功!";}
}

单点注销

单点注销其实就是在子系统的退出按钮上添加路径为http://www.zhongxin.com:8080/logout即可,然后在统一认证中心进行销毁全局会话的操作。

通过session.invalidate()进行销毁全局会话,该方法会执行session监听器的销毁方法。至于什么是监听器,上网查吧!

创建一个session会话监听器

该监听类继承HttpSessionListener实现两个方法,sessionDestroyed方法是sesison在销毁的时候执行的动作。

springboot项目加入session监听器和过滤器,都要加上@WebListener注解,在启动类上都要加上@ServletComponentScan(com.aaa)注解。

//session监听
@WebListener  //加到tomcat容器中  springboot项目加入session监听器和过滤器,都要加上@WebListener注解,在启动类上都要加上@ServletComponentScan注解
public class MySessionListener implements HttpSessionListener {@Overridepublic void sessionCreated(HttpSessionEvent se) {}/*** session销毁监听* @param se*/@Overridepublic void sessionDestroyed(HttpSessionEvent se) {HttpSession session = se.getSession();String token= (String) session.getAttribute("token");//删除token表中的数据DataBaseUtil.T_TOKEN.remove(token);List<ClientInfo> clientInfoList = DataBaseUtil.T_CLIENT_INFO.remove(token);try {//获取出注册的子系统,依次调用子系统登出的方法,也就是把子系统的session全部清除掉for(ClientInfo clientInfo:clientInfoList) {HttpUtil.sendHttpRequest(clientInfo.getClientUrl(), clientInfo.getJsessionid());}} catch (Exception e) {e.printStackTrace();}}
}

然后单点登录就搞定了。

补充:其实上面的单点注销并没有实现,不清楚哪里除了问题,不过后来通过一个简单的方法实现了,就是在session监听销毁中的HttpUtil.sendHttpRequest的url路径参数的进行字符串拼接然后改成了http:www.jiudian.com:8081/go这样的路径,然后分别在子系统的controller中添加go的映射方法,把session的isLogin设为false即可。虽然有点儿low,但是实现了!

六、手写单点登录的效果展示

首先把三个项目都启动起来。

然后先访问酒店管理系统,在浏览器发起请求http://www.jiudian.com:8081/main

然后会跳转到统一认证中心的登录页面

然后访问物流管理系统,在浏览器发起请求http://www.wuliu.com:8082/main

它还是会跳转到统一认证中心的登录页面

然后,重点来了,在酒店管理系统的登录下输入账号密码,进行登录

如果错误会重新返回登录页面,这里登录成功

然后会重定向到子系统酒店的欢迎页面

此时再去访问物流管理系统时,你会发现不用登录就直接进到物流管理系统的欢迎页了!

单点注销就不演示了,一个子系统进行退出之后,在统一认证中心销毁了全局会话信息,然后所有子系统都退出了!

七、知识点

1,@Slf4j日志

该日志是属于lombok插件的,安装lombok插件,或者在maven中并导入lombok依赖。

     <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.16.10</version><scope>provided</scope></dependency>

然后就可以使用了!

使用方法:在类上面加上注解@Slf4j,然后通过在代码中log.info()来打印日志。

2、springboot配置session监听器

session监听器由session对象调用invalidate()方法而调用,session监听器监听session的创建和销毁。

使用步骤:

在需要销毁session的地方写

session.invalidate();

然后就会调用session监听器的销毁方法,如果一个客户端一登录进来记录了session,那么会第一个就是进入session监听器的创建方法。

session监听器如何配置?

springboot项目加入session监听器和过滤器,都要加上@WebListener注解,在启动类上都要加上@ServletComponentScan(com.aaa)注解。
@ServletComponentScan注解一定要加包名进行扫描,否则扫描不到该监听器,具体扫描机制待以后研究!(都是经验,前辈趟过的路就不要走第二次了)

@WebListener
public class MySessionListener implements HttpSessionListener {@Overridepublic void sessionCreated(HttpSessionEvent se) {}@Overridepublic void sessionDestroyed(HttpSessionEvent se) { }
}

3、重定向发起http请求的方式

response重定向的方式,举个例子

public void redirectToSSOURL(HttpServletRequest request,HttpServletResponse response) {String redirectUrl = getRedirectUrl(request);//这句代码忽略,只是举个例子而已,不要管这个参数StringBuilder url = new StringBuilder(50).append("http://www.zhongxin.com:8080").append("/checkLogin?redirectUrl=").append(redirectUrl);//转发到注册中心response.sendRedirect(url.toString());}

这样重定向的路径就是http://www.zhongxin.com:8080/checkLogin?redirectUrl=XXX

return "redirect"重定向方式,再举个例子

 @RequestMapping("/checkLogin")public String show(){String redirectUrl="http://www.jiudian.com:8081";String token="test"return "redirect:"+redirectUrl+"?token="+token;}}

这样重定向的路径就是http://www.jiudian.com:8081?token=test

注意:只有重定向才能跨域发起请求,而转发只能在本系统进行转发,不能跨域。

八,结束语

真正企业级的单点登录肯定不会像上面那样实现,上面只是手写实现了单点登录,真正给企业部署单点登录的话就需要很多复杂性的内容了,而且还会考虑到更多安全性的问题。
原文链接:https://blog.csdn.net/weixin_44001965/article/details/103365351

【身份认证及权限控制一】单点登录相关推荐

  1. 用Python建设企业认证和权限控制平台

    目前大家对Python的了解更多来源是数据分析.AI.运维工具开发,在行业中使用Python进行web开发,同样也是非常受欢迎的,例如:FaceBook,豆瓣,知乎,饿了么等等,本文主要是介绍是利用P ...

  2. 企业级项目|用Python进行web开发企业统一用户认证和权限控制平台

    目前大家对Python的了解更多来源是数据分析.Ai.运维工具开发,在行业中使用Python进行web开发,同样也是非常受欢迎的,例如:FaceBook,豆瓣,知乎,饿了么等等,本文主要是介绍是利用P ...

  3. Springboot + Spring Security 实现前后端分离登录认证及权限控制

    Spring Security简介 Spring Security 是 Spring 家族中的一个安全管理框架,实际上,在 Spring Boot 出现之前,Spring Security 就已经发展 ...

  4. SpringBoot学习:整合shiro(身份认证和权限认证),使用EhCache缓存

    一.在pom中引入依赖jar包 1 <properties> 2 <shiro.version>1.3.2</shiro.version> 3 </prope ...

  5. Spring Security用户认证和权限控制(默认实现)

    1 背景 实际应用系统中,为了安全起见,一般都必备用户认证(登录)和权限控制的功能,以识别用户是否合法,以及根据权限来控制用户是否能够执行某项操作. Spring Security是一个安全相关的框架 ...

  6. shiro实现url级别的权限控制(用户登录)配置文件分析

    shiro实现url级别的权限控制(用户登录)

  7. SpringBoot+Security+Jwt登录认证与权限控制(一)

    一.相关技术 1. Maven 项目管理工具 2. MybatisPlus 3. SpringBoot 2.7.0 4. Security 安全框架 5. Jwt 6. easy-captcha 验证 ...

  8. Amazon 中国区配置 PingIdentity 身份集成实现 Redshift 数据库群集单点登录

    无疑使用单点登录 (SSO)访问组织中的多种应用程序能够提升用户体验 . 如果您负责为 Amazon Redshift 启用 SSO,则可以使用 ADFS.PingIdentity.Okta.Azur ...

  9. shiro 方法级别细粒度权限控制_Shiro的认证和权限控制

    从类别上分,有两大类: - 认证:你是谁?–识别用户身份. - 授权:你能做什么?–限制用户使用的功能. 权限的控制级别 从控制级别(模型)上分: - URL级别-粗粒度 - 方法级别-细粒度 - 页 ...

最新文章

  1. sql语句中having的作用是?
  2. 拯救你的久坐不起!用树莓派改造站立式办公桌:在随机时间升降,还有阻力检测功能...
  3. WINDOWS SERVER 2003从入门到精通之“域控制器安全策略”打开错误的解决方法
  4. k8s启动Pod遇到CrashLoopBackOff的解决方法
  5. qemu模拟执行固件文件(解决 Invalid ELF image for this architecture 问题)
  6. 【人物】养车点点费岸:给O2O产品经理的四点意见
  7. JavaScript模块化不算漫长的发展史
  8. 中兴c600olt数据配置_中兴天机Axon 10 Pro再掀波澜,4G版3199元起,5G版还有悬念?...
  9. 支付宝H5 与网页端支付开发
  10. nagios check_mysql uptime_nagios使用check_mysql监控mysql
  11. python实例 优化目标函数_Scipy优化算法--scipy.optimize.fmin_tnc()/minimize()
  12. 2015年自然语言处理实证方法会议(EMNLP)简介
  13. Spring配置属性文件
  14. jQuery(2)——如何使用jQuery回显数据
  15. 重置物体的position, rotation, scale,复制物体的组件
  16. 算法:判断对称树 101. Symmetric Tree
  17. 三个点在同一个半圆的概率_圆形水池中的四只小鸭子出现在同一个半圆中的概率是?...
  18. 疑难杂症篇(一)--安装Visio与已安装的office冲突的解决方案
  19. P2P终结者和反P2P终结者如何使用
  20. Java的ActiveX控件_注册ActiveX控件的几种方法 - 镜花水月 - JavaEye技术网站

热门文章

  1. 用于Web开发的8 个最好的跨平台编辑器
  2. Ubuntu linux 关机、重启、注销 命令
  3. PHP面向对象的进阶学习
  4. 产品所有者也应该是Scrum教练吗?
  5. php mysql生成excel文件,PHP导出MySQL数据到Excel文件简单示例
  6. elasticsearch狂神说笔记_神级学习笔记!别再说不会Elasticsearch了,这位架构师都整理好了...
  7. 网页全文搜索字符和全局搜索文件名【Edge和谷歌浏览器均适用】
  8. ug中文字大小设置_UG与AutoCAD的数据转换,原来还有这么简单的方法
  9. Java面对面向程序设计_语言与文化网课章节测试答案
  10. Hibernate环境搭建以及HelloWorld