父域 Cookie实现sso单点登录

单点登录(Single Sign On, SSO)是指在同一帐号平台下的多个应用系统中,用户只需登录一次,即可访问所有相互信任的应用系统。Cookie 的作用域由 domain 属性和 path 属性共同决定。在 Tomcat 中,domain 属性默认为当前域的域名/IP地址。path 属性的有效值是以“/”开头的路径,在 Tomcat 中,path 属性默认为当前 Web 应用的上下文路径。如果将 Cookie 的 domain 属性设置为当前域的父域,那么就认为它是父域 Cookie。Cookie 有一个特点,即父域中的 Cookie 被子域所共享,换言之,子域会自动继承父域中的Cookie。利用 Cookie 的这个特点,不难想到,将 Session ID(或 Token)保存到父域中不就行了。没错,我们只需要将 Cookie 的 domain 属性设置为父域的域名(主域名),同时将 Cookie 的 path 属性设置为根路径,这样所有的子域应用就都可以访问到这个 Cookie 了。不过这要求应用系统的域名需建立在一个共同的主域名之下,如 http://tieba.baidu.com 和 http://map.baidu.com,它们都建立在 http://baidu.com 这个主域名之下,那么它们就可以通过这种方式来实现单点登录。

配置host文件

项目结构

引入依赖

父项目引入依赖,子项目无依赖引入

         <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.24</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId><version>2.6.7</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version></dependency>

login系统

前端部分

login.html页面,负责显示登录页面并提交登录

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head><meta charset="UTF-8"><title>Login Module</title>
</head>
<body><h1>用户登录 </h1><p style="color: red;" th:text="${session.msg}"></p><form action="/login" method="POST">姓名:  <input name="username" value=""><br></br>密码:  <input name="password" value=""><br></br><button type="submit" style="width:60px;height:30px"> login </button></form></body>
</html>

后端部分

跳转登录页面 

import com.sso.login.pojo.User;
import com.sso.login.utils.LogCacheUtil;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.thymeleaf.util.StringUtils;import javax.servlet.http.Cookie;
import javax.servlet.http.HttpSession;@Controller
@RequestMapping("/view")
public class ViewController {/*** 跳转到登录页面* @return*/@GetMapping("/login")public String toLogin(@RequestParam(required = false, defaultValue = "") String target,HttpSession session,@CookieValue(required = false, value = "TOKEN") Cookie cookie){if(StringUtils.isEmpty(target)){target = "login.codeshop.com:9010";}if(cookie != null){// 从父域拿到tokenString value = cookie.getValue();User user = LogCacheUtil.loginUser.get(value);if(user != null){return "redirect:" + target;}}session.setAttribute("target",target);return "login";}}

负责登录校验以及解析token 

import com.sso.login.pojo.User;
import com.sso.login.utils.LogCacheUtil;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.thymeleaf.util.StringUtils;import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;@Controller
@RequestMapping("/login")
public class LoginController {private static Set<User> dbUser;// 模拟数据库static {dbUser = new HashSet<>();dbUser.add(new User(1, "zxb", "1234567"));dbUser.add(new User(2, "admin", "123456"));}@PostMappingpublic String doLogin(User user, HttpSession session, HttpServletResponse response) {String target = (String) session.getAttribute("target");// 验证登录Optional<User> first = dbUser.stream().filter(dbUser -> dbUser.getUsername().equals(user.getUsername()) &&dbUser.getPassword().equals(user.getPassword())).findFirst();if (first.isPresent()) {String token = UUID.randomUUID().toString();// 保存token到父域 CookieCookie cookie = new Cookie("TOKEN", token);cookie.setPath("/");cookie.setDomain("codeshop.com");response.addCookie(cookie);// 登录成功保存到LogCacheUtil工具类中,这个部分可以用redis去实现LogCacheUtil.loginUser.put(token, first.get());} else {session.setAttribute("msg", "用户名或密码错误!");// 错误跳转到登录页面return "login";}// 重定向到目标地址return "redirect:" + target;}@GetMapping("info")@ResponseBodypublic ResponseEntity<User> getUserInfo(String token) {if (!StringUtils.isEmpty(token)) {// 验证token并从token获取用户信息并返回User user = LogCacheUtil.loginUser.get(token);return ResponseEntity.ok(user);} else {return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);}}@GetMapping("/logout")public String loginOut(@CookieValue(value = "TOKEN") Cookie cookie, HttpServletResponse response, String target) {cookie.setMaxAge(0);LogCacheUtil.loginUser.remove(cookie.getValue());response.addCookie(cookie);return "redirect:" + target;}
}

model

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;@Data //添加getter/setter
@NoArgsConstructor  //添加无参构造器
@AllArgsConstructor //添加全参构造器
@Accessors(chain = true) //添加链式调用
public class User {private Integer id;private String username;private String password;
}

保存User工具类

import com.sso.login.pojo.User;import java.util.HashMap;
import java.util.Map;public class LogCacheUtil {public static Map<String, User> loginUser = new HashMap<>();}

Main系统

前端部分

index.html页面 

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head><meta charset="UTF-8"><title>Index Module</title>
</head>
<body><h1>欢迎登录!</h1><span><a th:if="${session.loginUser == null}" href="http://login.codeshop.com:9000/view/login?target=http://login.codeshop.com:9010/view/index">login</a><a th:unless="${session.loginUser == null}" href="http://login.codeshop.com:9000/login/logout?target=http://www.codeshop.com:9010/view/index">logout</a></span><p th:unless="${session.loginUser == null}"><span style="color:deepskyblue" th:text="${session.loginUser.username}"></span> 已登录!<br></br><br></br>id: <span style="color:deepskyblue" th:text="${session.loginUser.id}"></span><br></br>username: <span style="color:deepskyblue" th:text="${session.loginUser.username}"></span><br></br></p>
</body>
</html>

后端部分 

Viewcontroller

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.client.RestTemplate;
import org.thymeleaf.util.StringUtils;import javax.servlet.http.Cookie;
import javax.servlet.http.HttpSession;
import java.util.Map;@Controller
@RequestMapping("/view")
public class ViewController {@Autowiredprivate RestTemplate restTemplate;private final String USER_INFO_ADDRESS = "http://login.codeshop.com:9000/login/info?token=";@GetMapping("/index")public String toIndex(@CookieValue(required = false, value = "TOKEN") Cookie cookie,HttpSession session) {if (cookie != null) {String token = cookie.getValue();if (!StringUtils.isEmpty(token)) {Map result = restTemplate.getForObject(USER_INFO_ADDRESS + token, Map.class);session.setAttribute("loginUser", result);}}return "index";}
}

配置restTemplate的HTTP客户端工具

@SpringBootApplication
public class MainApp {public static void main(String[] args) {SpringApplication.run(MainApp.class,args);}@Beanpublic RestTemplate restTemplate(){return new RestTemplate();}
}

cart系统

前端部分

index.html页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head><meta charset="UTF-8"><title>Blog Module</title>
</head>
<body><h1>登录页面 !</h1><span><a th:if="${session.loginUser == null}" href="http://login.codeshop.com:9000/view/login?target=http://cart.codeshop.com:9012/view/index">login</a><a th:unless="${session.loginUser == null}" href="http://login.codeshop.com:9000/login/logout?target=http://cart.codeshop.com:9012/view/index">logout</a></span><p th:unless="${session.loginUser == null}"><span style="color:deeppink" th:text="${session.loginUser.username}"></span> 已登录!<br></br><br></br>id: <span style="color:deeppink" th:text="${session.loginUser.id}"></span><br></br>username: <span style="color:deeppink" th:text="${session.loginUser.username}"></span><br></br></p>
</body>
</html>

后端部分 

view的controller

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.client.RestTemplate;
import org.thymeleaf.util.StringUtils;import javax.servlet.http.Cookie;
import javax.servlet.http.HttpSession;
import java.util.Map;@Controller
@RequestMapping("/view")
public class ViewController {@Autowiredprivate RestTemplate restTemplate;private final String USER_INFO_ADDRESS = "http://login.codeshop.com:9000/login/info?token=";@GetMapping("/index")public String toIndex(@CookieValue(required = false, value = "TOKEN") Cookie cookie,HttpSession session){if(cookie != null){// 从cookie拿到的token去请求获取用户信息需要去实现验证String token = cookie.getValue();if(!StringUtils.isEmpty(token)){Map result = restTemplate.getForObject(USER_INFO_ADDRESS+token,Map.class);session.setAttribute("loginUser",result);}}return "index";}
}

配置restTemplate的HTTP客户端工具

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;@SpringBootApplication
public class CartApp {public static void main(String[] args) {SpringApplication.run(CartApp.class,args);}@Beanpublic RestTemplate restTemplate(){return new RestTemplate();}
}

测试

启动

访问 mainApp

登录

 登录成功

输入cart.codeshop.com:9012/view/index,直接访问cart系统成功

 输入www.codeshop.com:9010/view/index,直接访问main系统成功

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/79804.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python浪漫星空

系列文章 序号文章目录直达链接1浪漫520表白代码https://want595.blog.csdn.net/article/details/1306668812满屏表白代码https://want595.blog.csdn.net/article/details/1297945183跳动的爱心https://want595.blog.csdn.net/article/details/1295031234漂浮爱心https://wan…

校园网web免认真,大量服务器

服务器加满了&#xff0c;没有几个人来&#xff0c;传点图片看实力 什么方法解web认证方式校园网&#xff1f; 一般的校园网是对学生免费开放的&#xff0c;假如你是学生输入学号密码上网就是了&#xff0c;假如你不是那就是想蹭网了&#xff0c;再假如你不想让管理员或上网行为…

数据分享|R语言逻辑回归、线性判别分析LDA、GAM、MARS、KNN、QDA、决策树、随机森林、SVM分类葡萄酒交叉验证ROC...

全文链接:http://tecdat.cn/?p27384 在本文中&#xff0c;数据包含有关葡萄牙“Vinho Verde”葡萄酒的信息&#xff08;点击文末“阅读原文”获取完整代码数据&#xff09;。 介绍 该数据集&#xff08;查看文末了解数据获取方式&#xff09;有1599个观测值和12个变量&#xf…

pdf添加水印

给pdf文件添加水印 引入依赖 <dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.5.13.3</version></dependency>添加水印 package com.it2.pdfdemo02.util;import com.itextpdf.tex…

用 Pytest+Allure 生成漂亮的 HTML 图形化测试报告

本篇文章将介绍如何使用开源的测试报告生成框架 Allure 生成规范、格式统一、美观的测试报告。 通过这篇文章的介绍&#xff0c;你将能够&#xff1a; 将 Allure 与 Pytest 测试框架相结合&#xff1b; 如何定制化测试报告内容 执行测试之后&#xff0c;生成 Allure 格式的测…

免费和开源的机器翻译软件LibreTranslate

什么是 LibreTranslate &#xff1f; LibreTranslate 免费开源机器翻译 API&#xff0c;完全自托管。与其他 API 不同&#xff0c;它不依赖于 Google 或 Azure 等专有提供商来执行翻译。它的翻译引擎由开源 Argos Translate 库提供支持。 这个软件在 2022 年 3 月的时候折腾过&…

【图论】有向图的强连通分量

算法提高课笔记 文章目录 理论基础SCC板子 例题受欢迎的牛题意思路代码 学校网络题意思路代码 最大半连通子图题意思路代码 银河题意思路代码 理论基础 什么是连通分量&#xff1f; 对于一个有向图&#xff0c;分量中任意两点u&#xff0c;v&#xff0c;必然可以从u走到v&am…

Web安全与攻防

Web安全概述 在Internet大众化及Web技术飞速演变的今天&#xff0c;在线安全所面临的挑战日益严峻。伴随着在线信息和服务的可用性的提升&#xff0c;以及基于Web的攻击和破坏的增长&#xff0c;安全风险达到了前所未有的高度。Web安全可以从以下三个方面进行考虑&#xff1a;…

Jmeter系列-控制器Controllers的介绍(8)

Controllers 简介 JMeter是一款功能强大的性能测试工具&#xff0c;而控制器是JMeter中非常重要的一个组件。控制器用于控制测试计划的执行流程&#xff0c;可以根据需求来控制线程的启动、停止、循环等操作。 Jmeter有两种类型的控制器&#xff1a;Samplers&#xff08;取样…

【Linux】动静态库

目录 1.静态库2.动态库3.静态库的使用区别总结 1.静态库 我们在linux中已经帮我们下载好了C和C所需要的各种库&#xff0c;库也是文件&#xff0c;实际上就是各种接口的实现&#xff0c;我们在使用系统提供的譬如printf等函数时&#xff0c;就是使用系统中的库文件。使用一个库…

驱动开发,IO多路复用实现过程,epoll方式

1.框架图 被称为当前时代最好用的io多路复用方式&#xff1b; 核心操作&#xff1a;一棵树&#xff08;红黑树&#xff09;、一张表&#xff08;内核链表&#xff09;以及三个接口&#xff1b; 思想&#xff1a;&#xff08;fd代表文件描述符&#xff09; epoll要把检测的事件…

Vue Router入门:为Vue.js应用添加导航

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

【Unity】ShaderGraph应用(浮动气泡)

【Unity】ShaderGraph应用(浮动气泡) 实现效果 一、实现的方法 1.使用节点介绍 Position&#xff1a;获取模型的顶点坐标 Simple Noise:简单的噪声&#xff0c;用于计算顶点抖动 Fresnel Effect&#xff1a;菲涅耳效应&#xff0c;用于实现气泡效果 计算用节点 Add&…

jmeter生成html格式接口自动化测试报告

jmeter自带执行结果查看的插件&#xff0c;但是需要在jmeter工具中才能查看&#xff0c;如果要向领导提交测试结果&#xff0c;不够方便直观。 笔者刚做了这方面的尝试&#xff0c;总结出来分享给大家。 这里需要用到ant来执行测试用例并生成HTML格式测试报告。 一、ant下载安…

XSS入门 XSS Challenges

level1(直接注入) <script>alert(xss)</script>level2(双引号闭合标签) 测试 <sCr<ScRiPt>IPT>OonN"\/(hrHRefEF)</sCr</ScRiPt>IPT>发现<>"被转换&#xff0c;构造新的语句 "><script>alert(/xss/)</…

Keepalived 高可用(附带配置实例,联动Nginx和LVS)

Keepalived 一、Keepalived相关知识点概述1.1 单服务的风险&#xff08;单点故障问题&#xff09;1.2 一个合格的集群应该具备的特性1.3 VRRP虚拟路由冗余协议1.4 健康检查1.5 ”脑裂“现象 二、Keepalived2.1 Keepalived是什么&#xff1f;2.2 Keepalived体系主要模块及其作用…

任意文件下载

原理&#xff1a; 文件查看或文件下载功能&#xff0c;不做限制&#xff0c;恶意用户就能够查看或下载任意敏感文件&#xff0c;这就是文件查看与下载漏洞。 一般链接形式: download.php?path down.php?file data.php?file download.php?filename 或者包含参数: &Sr…

数据结构:树的概念和结构

文章目录 1. 树的概念2. 树的结构3. 树的相关概念4. 树的表示孩子表示法双亲表示法孩子兄弟表示法 5. 树在实际中的应用 1. 树的概念 树是一种非线性的数据结构,它是由 n (n > 0)个有限结点组成一个具有层次关系的. 把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝…

.360勒索病毒和.halo勒索病毒数据恢复|金蝶、用友、ERP等数据恢复

导言&#xff1a; 随着数字化时代的持续发展&#xff0c;网络安全威胁也变得前所未有地复杂和难以应对。在这个充满挑战的网络环境中&#xff0c;勒索病毒已经成为了一种极为危险和破坏性的威胁。最近引起广泛关注的是.360勒索病毒&#xff0c;一种可怕的恶意软件&#xff0c;…

Python实现自主售卖机

1 问题 在python中我们常常使用到条件判断&#xff0c;if语句时常见的条件判断语句之一。那么如何使用if语句实现根据情况自动选择商品进行售卖呢&#xff1f; 2 方法 根据if语句执行时从上往下执行的特点&#xff0c;使用if语句、dict和list来实现整个流程。 代码清单 1 drink…