1、目的
跨域名和跨作用域实现多个系统或者是服务之间,实现一处登录,处处登录。
2、构成
客户端1:用于模拟系统1;
客户端2:用于模仿系统2;
认证服务端server:用于用户认证;
3、思路:
1、客户端1想要访问客户端1(http://client1.com:8081/employees)的内容,必须先登录。
2、首次访问客户端1的内容,没有登录信息,必须先进行认证登录,所以就跳转去了认证服务端server的认证页面进行认证登录。
【跳转的同时,带上一个参数,就是客户端1访问接口的地址:
return "redirect:http://sso.com:8080/login.html?redirect_url=http://client1.com:8081/employees";
】
3、认证服务端server,接收到了客户端1的跳转地址,先验证浏览器有没有sessin和redis有没有sso_token,如果没有,就跳转到登录页面;【留下个彩蛋,供客户端2进行使用】
4、输入账号密码后,认证服务登录成功,【设置了cookie和redis的sso_token】所以就跳转到了客户端1的访问接口,因为已经认证过了,所以可以直接进行内容的访问。
5、如果是说客户端2进行了接口(http://client2.com:8082/employees)内容的访问,但是客户端2什么登录信息也没有,所以跳转到了认证服务端server,到了第三步,此时用户1已经在第四步设置了sso_token和cookie,所以用户2是有sso_token和cookie【就是步骤3的彩蛋】的,所以直接跳转到客户端2的访问接口。
代码信息:
客户端1:
- package com.pshdhx.gulimalltestssoclient1.controller;
-
- import org.springframework.http.ResponseEntity;
- import org.springframework.stereotype.Controller;
- import org.springframework.ui.Model;
- import org.springframework.util.StringUtils;
- import org.springframework.web.bind.annotation.GetMapping;
- import org.springframework.web.bind.annotation.RequestParam;
- import org.springframework.web.client.RestTemplate;
-
- import javax.servlet.http.HttpSession;
- import java.util.ArrayList;
- import java.util.List;
-
- /**
- * @author pshdhx
- * @date 2022-08-29 20:55
- * @Des
- * @Method
- * @Summary
- */
- @Controller
- public class LoginController {
- @GetMapping("/employees")
- public String employees(Model model, HttpSession session,
- @RequestParam(name="token",required = false) String token){
- if(!StringUtils.isEmpty(token)){
- //根据token去sso认证中心去获取信息
- RestTemplate restTemplate = new RestTemplate();
- ResponseEntity
entity = restTemplate.getForEntity("http://sso.com:8080/userinfo?token=" + token, String.class); - session.setAttribute("loginUser", entity.getBody());
- }
- Object loginUser = session.getAttribute("loginUser");
- if(loginUser == null && token == null){
- // 未登录,跳转认证服务器登录
- return "redirect:http://sso.com:8080/login.html?redirect_url=http://client1.com:8081/employees";
- }else {
- // 登录状态显示
- List
emps = new ArrayList<>(); - emps.add("张三");
- emps.add("李四");
- model.addAttribute("emps", emps);
- return "employees";
- }
- }
- }
配置信息:
- server.port=8081
- server.servlet.session.timeout=30m
- spring.session.store-type=redis
- spring.redis.host=xxxxxxxxxxxxxxxxxxxxxxx
客户端2:
- package com.pshdhx.gulimalltestssoclient2.controller;
-
- import org.springframework.http.ResponseEntity;
- import org.springframework.stereotype.Controller;
- import org.springframework.ui.Model;
- import org.springframework.util.StringUtils;
- import org.springframework.web.bind.annotation.GetMapping;
- import org.springframework.web.bind.annotation.RequestParam;
- import org.springframework.web.client.RestTemplate;
-
- import javax.servlet.http.HttpSession;
- import java.util.ArrayList;
- import java.util.List;
-
- /**
- * @author pshdhx
- * @date 2022-08-29 20:55
- * @Des
- * @Method
- * @Summary
- */
- @Controller
- public class LoginController {
-
- /**
- * 需要登录状态访问
- */
- @GetMapping(value = "/employees")
- public String employees(Model model, HttpSession session,
- @RequestParam(name = "token", required = false) String token) {
- if (!StringUtils.isEmpty(token)) {
- // 根据token去sso认证中心获取用户信息
- RestTemplate restTemplate = new RestTemplate();
- ResponseEntity
entity = restTemplate.getForEntity("http://sso.com:8080/userinfo?token=" + token, String.class); - session.setAttribute("loginUser", entity.getBody());
- }
- Object loginUser = session.getAttribute("loginUser");
- if (loginUser == null && token == null) {
- // 未登录,跳转认证服务器登录
- return "redirect:http://sso.com:8080/login.html?redirect_url=http://client2.com:8082/employees";
- } else {
- // 登录状态显示
- List
emps = new ArrayList<>(); - emps.add("张三");
- emps.add("李四");
- model.addAttribute("emps", emps);
- return "employees";
- }
-
- }
- }
- server.port=8082
- server.servlet.session.timeout=30m
- spring.session.store-type=redis
- spring.redis.host=xxxxxxxxxxxxx
认证服务端:
- package com.pshdhx.gulimall.testssoserver.controller;
-
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.data.redis.core.StringRedisTemplate;
- import org.springframework.stereotype.Controller;
- import org.springframework.ui.Model;
- import org.springframework.util.StringUtils;
- import org.springframework.web.bind.annotation.*;
-
- import javax.servlet.http.Cookie;
- import javax.servlet.http.HttpServletResponse;
- import java.util.UUID;
-
- /**
- * @author pshdhx
- * @date 2022-08-29 21:06
- * @Des
- * @Method
- * @Summary
- */
- @Controller
- public class LoginServerController {
- @Autowired
- StringRedisTemplate redisTemplate;
-
- /**
- * 供其他应用获取用户信息的接口
- * @param token
- * @return
- */
- @ResponseBody
- @GetMapping("/userinfo")
- public String userInfo(@RequestParam("token") String token) {
- String username = redisTemplate.opsForValue().get(token);
- return username;
- }
-
- /**
- * 访问登录页
- * @param url 登录成功回调页
- * @param token cookie值
- */
- @GetMapping(value = "/login.html")
- public String login(@RequestParam("redirect_url") String url, Model model,
- @CookieValue(value = "sso_token", required = false) String token) {
- // 根据token获取用户信息【这一块是针对于客户端2进行共享的,因为客户端1设置了cookie,所以客户端2才能共享到此sso_token】
- if (!StringUtils.isEmpty(token)) {
- String username = redisTemplate.opsForValue().get(token);
- if (!StringUtils.isEmpty(username)) {
- // token正确,已登录状态,跳转回客户端【当前访问客户端共享了其他客户端的登录状态】
- return "redirect:" + url + "?token=" + token;
- }
- }
- // 不存在sso_token,未登录返回登录页,并将回调地址链路下传
- model.addAttribute("url", url);
- return "login";
- }
-
- /**
- * 登录
- * @param url 登录成功回调页
- */
- @PostMapping(value = "/doLogin")
- public String doLogin(String username, String password, String url,
- Model model, HttpServletResponse response) {
- if (!StringUtils.isEmpty(username) && !StringUtils.isEmpty(password)) {
- // 登录成功,跳转回调页
- String token = UUID.randomUUID().toString().replace("-", "");
- // token作为key,用户信息作为value存入redis中
- redisTemplate.opsForValue().set(token, username);
- // 在sso.com域名下设置cookie,使得不同客户端访问单点登录时可以带上cookie值成功登录
- Cookie cookie = new Cookie("sso_token", token);
- response.addCookie(cookie);
- return "redirect:" + url + "?token=" + token;
- }
- // 登录失败
- model.addAttribute("url", url);
- return "login";
- }
- }
- server.port=8080
- server.servlet.session.timeout=30m
- spring.redis.host=xxxxxxxxxxxxxxxxxxxxxxx
- html>
- <html lang="en" xmlns:th="http://www.thymeleaf.org">
- <head>
- <meta charset="UTF-8">
- <title>登录页title>
- head>
- <body>
- <form action="/doLogin" method="post">
- 用户名:<input type="text" name="username"/><br/>
- 密码:<input type="password" name="password"/><br/>
- <input type="hidden" name="url" th:value="${url}">
- <input type="submit" value="登录">
- form>
- body>
- html>
单点登录代码学习: