• 父域 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文件

    项目结构

    引入依赖

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

    1. <dependency>
    2. <groupId>org.springframework.boot</groupId>
    3. <artifactId>spring-boot-starter-web</artifactId>
    4. </dependency>
    5. <dependency>
    6. <groupId>org.projectlombok</groupId>
    7. <artifactId>lombok</artifactId>
    8. <version>1.18.24</version>
    9. </dependency>
    10. <dependency>
    11. <groupId>org.springframework.boot</groupId>
    12. <artifactId>spring-boot-starter-thymeleaf</artifactId>
    13. <version>2.6.7</version>
    14. </dependency>
    15. <dependency>
    16. <groupId>javax.servlet</groupId>
    17. <artifactId>javax.servlet-api</artifactId>
    18. <version>4.0.1</version>
    19. </dependency>

    login系统

    前端部分

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

    1. html>
    2. <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
    3. <head>
    4. <meta charset="UTF-8">
    5. <title>Login Moduletitle>
    6. head>
    7. <body>
    8. <h1>用户登录 h1>
    9. <p style="color: red;" th:text="${session.msg}">p>
    10. <form action="/login" method="POST">
    11. 姓名: <input name="username" value="">
    12. <br>br>
    13. 密码: <input name="password" value="">
    14. <br>br>
    15. <button type="submit" style="width:60px;height:30px"> login button>
    16. form>
    17. body>
    18. html>

    后端部分

    跳转登录页面 

    1. import com.sso.login.pojo.User;
    2. import com.sso.login.utils.LogCacheUtil;
    3. import org.springframework.stereotype.Controller;
    4. import org.springframework.web.bind.annotation.CookieValue;
    5. import org.springframework.web.bind.annotation.GetMapping;
    6. import org.springframework.web.bind.annotation.RequestMapping;
    7. import org.springframework.web.bind.annotation.RequestParam;
    8. import org.thymeleaf.util.StringUtils;
    9. import javax.servlet.http.Cookie;
    10. import javax.servlet.http.HttpSession;
    11. @Controller
    12. @RequestMapping("/view")
    13. public class ViewController {
    14. /**
    15. * 跳转到登录页面
    16. * @return
    17. */
    18. @GetMapping("/login")
    19. public String toLogin(@RequestParam(required = false, defaultValue = "") String target,
    20. HttpSession session,
    21. @CookieValue(required = false, value = "TOKEN") Cookie cookie){
    22. if(StringUtils.isEmpty(target)){
    23. target = "login.codeshop.com:9010";
    24. }
    25. if(cookie != null){
    26. // 从父域拿到token
    27. String value = cookie.getValue();
    28. User user = LogCacheUtil.loginUser.get(value);
    29. if(user != null){
    30. return "redirect:" + target;
    31. }
    32. }
    33. session.setAttribute("target",target);
    34. return "login";
    35. }
    36. }

    负责登录校验以及解析token 

    1. import com.sso.login.pojo.User;
    2. import com.sso.login.utils.LogCacheUtil;
    3. import org.springframework.http.HttpStatus;
    4. import org.springframework.http.ResponseEntity;
    5. import org.springframework.stereotype.Controller;
    6. import org.springframework.web.bind.annotation.CookieValue;
    7. import org.springframework.web.bind.annotation.GetMapping;
    8. import org.springframework.web.bind.annotation.PostMapping;
    9. import org.springframework.web.bind.annotation.RequestMapping;
    10. import org.springframework.web.bind.annotation.ResponseBody;
    11. import org.thymeleaf.util.StringUtils;
    12. import javax.servlet.http.Cookie;
    13. import javax.servlet.http.HttpServletResponse;
    14. import javax.servlet.http.HttpSession;
    15. import java.util.HashSet;
    16. import java.util.Optional;
    17. import java.util.Set;
    18. import java.util.UUID;
    19. @Controller
    20. @RequestMapping("/login")
    21. public class LoginController {
    22. private static Set dbUser;
    23. // 模拟数据库
    24. static {
    25. dbUser = new HashSet<>();
    26. dbUser.add(new User(1, "zxb", "1234567"));
    27. dbUser.add(new User(2, "admin", "123456"));
    28. }
    29. @PostMapping
    30. public String doLogin(User user, HttpSession session, HttpServletResponse response) {
    31. String target = (String) session.getAttribute("target");
    32. // 验证登录
    33. Optional first = dbUser.stream().filter(dbUser -> dbUser.getUsername().equals(user.getUsername()) &&
    34. dbUser.getPassword().equals(user.getPassword()))
    35. .findFirst();
    36. if (first.isPresent()) {
    37. String token = UUID.randomUUID().toString();
    38. // 保存token到父域 Cookie
    39. Cookie cookie = new Cookie("TOKEN", token);
    40. cookie.setPath("/");
    41. cookie.setDomain("codeshop.com");
    42. response.addCookie(cookie);
    43. // 登录成功保存到LogCacheUtil工具类中,这个部分可以用redis去实现
    44. LogCacheUtil.loginUser.put(token, first.get());
    45. } else {
    46. session.setAttribute("msg", "用户名或密码错误!");
    47. // 错误跳转到登录页面
    48. return "login";
    49. }
    50. // 重定向到目标地址
    51. return "redirect:" + target;
    52. }
    53. @GetMapping("info")
    54. @ResponseBody
    55. public ResponseEntity getUserInfo(String token) {
    56. if (!StringUtils.isEmpty(token)) {
    57. // 验证token并从token获取用户信息并返回
    58. User user = LogCacheUtil.loginUser.get(token);
    59. return ResponseEntity.ok(user);
    60. } else {
    61. return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);
    62. }
    63. }
    64. @GetMapping("/logout")
    65. public String loginOut(@CookieValue(value = "TOKEN") Cookie cookie, HttpServletResponse response, String target) {
    66. cookie.setMaxAge(0);
    67. LogCacheUtil.loginUser.remove(cookie.getValue());
    68. response.addCookie(cookie);
    69. return "redirect:" + target;
    70. }
    71. }

    model

    1. import lombok.AllArgsConstructor;
    2. import lombok.Data;
    3. import lombok.NoArgsConstructor;
    4. import lombok.experimental.Accessors;
    5. @Data //添加getter/setter
    6. @NoArgsConstructor //添加无参构造器
    7. @AllArgsConstructor //添加全参构造器
    8. @Accessors(chain = true) //添加链式调用
    9. public class User {
    10. private Integer id;
    11. private String username;
    12. private String password;
    13. }

    保存User工具类

    1. import com.sso.login.pojo.User;
    2. import java.util.HashMap;
    3. import java.util.Map;
    4. public class LogCacheUtil {
    5. public static Map loginUser = new HashMap<>();
    6. }

    Main系统

    前端部分

    index.html页面 

    1. "en" xmlns:th="http://www.w3.org/1999/xhtml">
    2. "UTF-8">
    3. Index Module
    4. 欢迎登录!

    5. "${session.loginUser == null}">

    6. "color:deepskyblue" th:text="${session.loginUser.username}"> 已登录!



    7. id: "color:deepskyblue" th:text="${session.loginUser.id}">

    8. username: "color:deepskyblue" th:text="${session.loginUser.username}">

    后端部分 

    Viewcontroller

    1. import org.springframework.beans.factory.annotation.Autowired;
    2. import org.springframework.stereotype.Controller;
    3. import org.springframework.web.bind.annotation.CookieValue;
    4. import org.springframework.web.bind.annotation.GetMapping;
    5. import org.springframework.web.bind.annotation.RequestMapping;
    6. import org.springframework.web.client.RestTemplate;
    7. import org.thymeleaf.util.StringUtils;
    8. import javax.servlet.http.Cookie;
    9. import javax.servlet.http.HttpSession;
    10. import java.util.Map;
    11. @Controller
    12. @RequestMapping("/view")
    13. public class ViewController {
    14. @Autowired
    15. private RestTemplate restTemplate;
    16. private final String USER_INFO_ADDRESS = "http://login.codeshop.com:9000/login/info?token=";
    17. @GetMapping("/index")
    18. public String toIndex(@CookieValue(required = false, value = "TOKEN") Cookie cookie,
    19. HttpSession session) {
    20. if (cookie != null) {
    21. String token = cookie.getValue();
    22. if (!StringUtils.isEmpty(token)) {
    23. Map result = restTemplate.getForObject(USER_INFO_ADDRESS + token, Map.class);
    24. session.setAttribute("loginUser", result);
    25. }
    26. }
    27. return "index";
    28. }
    29. }

    配置restTemplate的HTTP客户端工具

    1. @SpringBootApplication
    2. public class MainApp {
    3. public static void main(String[] args) {
    4. SpringApplication.run(MainApp.class,args);
    5. }
    6. @Bean
    7. public RestTemplate restTemplate(){
    8. return new RestTemplate();
    9. }
    10. }

    cart系统

    前端部分

    index.html页面

    1. "en" xmlns:th="http://www.w3.org/1999/xhtml">
    2. "UTF-8">
    3. Blog Module
    4. 登录页面 !

    5. "${session.loginUser == null}">

    6. "color:deeppink" th:text="${session.loginUser.username}"> 已登录!



    7. id: "color:deeppink" th:text="${session.loginUser.id}">

    8. username: "color:deeppink" th:text="${session.loginUser.username}">

    后端部分 

    view的controller

    1. import org.springframework.beans.factory.annotation.Autowired;
    2. import org.springframework.stereotype.Controller;
    3. import org.springframework.web.bind.annotation.CookieValue;
    4. import org.springframework.web.bind.annotation.GetMapping;
    5. import org.springframework.web.bind.annotation.RequestMapping;
    6. import org.springframework.web.client.RestTemplate;
    7. import org.thymeleaf.util.StringUtils;
    8. import javax.servlet.http.Cookie;
    9. import javax.servlet.http.HttpSession;
    10. import java.util.Map;
    11. @Controller
    12. @RequestMapping("/view")
    13. public class ViewController {
    14. @Autowired
    15. private RestTemplate restTemplate;
    16. private final String USER_INFO_ADDRESS = "http://login.codeshop.com:9000/login/info?token=";
    17. @GetMapping("/index")
    18. public String toIndex(@CookieValue(required = false, value = "TOKEN") Cookie cookie,
    19. HttpSession session){
    20. if(cookie != null){
    21. // 从cookie拿到的token去请求获取用户信息需要去实现验证
    22. String token = cookie.getValue();
    23. if(!StringUtils.isEmpty(token)){
    24. Map result = restTemplate.getForObject(USER_INFO_ADDRESS+token,Map.class);
    25. session.setAttribute("loginUser",result);
    26. }
    27. }
    28. return "index";
    29. }
    30. }

    配置restTemplate的HTTP客户端工具

    1. import org.springframework.boot.SpringApplication;
    2. import org.springframework.boot.autoconfigure.SpringBootApplication;
    3. import org.springframework.context.annotation.Bean;
    4. import org.springframework.web.client.RestTemplate;
    5. @SpringBootApplication
    6. public class CartApp {
    7. public static void main(String[] args) {
    8. SpringApplication.run(CartApp.class,args);
    9. }
    10. @Bean
    11. public RestTemplate restTemplate(){
    12. return new RestTemplate();
    13. }
    14. }

    测试

    启动

    访问 mainApp

    登录

     登录成功

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

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

  • 相关阅读:
    当添加一个键值对元素时,HashMap发生了什么?
    软件企业需要每年年审吗?
    Java开发基础_04
    Matlab最小二乘平面拟合(SVD方法)—点云处理及可视化第3期
    【软件安装】Linux中RabbitMQ的安装
    shell实现日期加减
    LeetCode回溯算法子序列问题——491. 递增子序列
    CMS详解
    关于如何检查一个进程是否存活
    CSRF漏洞分析
  • 原文地址:https://blog.csdn.net/qq_63431773/article/details/132866159