springboot 單點登錄(詳細代碼)

單點登錄,就是在一個系統登錄後,在它的關聯繫統也不用重新登錄了。例如:你成功登錄了淘寶,那麼在天貓也就成功登錄了;同理,退出也是一樣的。在天貓退出賬號,在淘寶的賬號也就退出了。(咳咳,同一瀏覽器內)

實現單點登錄,主要就是利用同域名傳遞 cookie 中的登錄用戶信息。以下是一種實現方式,僅供參考!

準備工作

1)
系統:win10
IDE:sts4
springboot2.2.4.RELEASE、 jdk8、 maven3.3.9

在本例中,創建了4個 springboot 項目,一個專用來處理登錄(login.sso.com),其他都是關聯繫統,把 sys1.sso.com 當做是主系統。

如果用戶首先在 sys1 系統的首頁瀏覽,此時點擊登錄,則跳轉到登錄系統處理登錄邏輯。登錄成功後,會跳轉到 sys1 系統的首頁,並且是已登錄狀態。
同理用戶在 sys2 系統的首頁瀏覽,此時點擊登錄,則跳轉到登錄系統處理登錄邏輯。登錄成功後,會跳轉到 sys2 系統的首頁,並且是已登錄狀態。
那如果一開始就是沒有在其他系統瀏覽,而是直接到登錄系統進行登錄呢。那這種情況登錄成功後,本例會跳轉到 sys1 的首頁,即設定 sys1 爲主系統的意思

2)域名映射
修改 hosts 文件,路徑:C:\Windows\System32\drivers\etc
在這裏插入圖片描述

登錄系統

登錄系統只有一個登錄界面和處理登錄信息的邏輯
1)pom 依賴

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

沒有使用數據庫,用戶信息是寫死的,所以只需要這兩個依賴就夠了。

2)登錄界面 login.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>sso-login</title>
</head>
<body>
	<h3>這裏是登錄頁面</h3>
	<p style="color:red;" th:text="${session.msg}"></p>
	<form action="/login" method="post">
		用戶名:<input type="text" name="uname"/><br/>
		密碼:<input type="password" name="upwd"/><br/>
		<button type="submit">登錄</button>
	</form>
</body>
</html>

3)控制層及其他

public class User {

	private String uname;
	private String upwd;
	public User(String uname, String upwd) {
		super();
		this.uname = uname;
		this.upwd = upwd;
	}
	public String getUname() {
		return uname;
	}
	public void setUname(String uname) {
		this.uname = uname;
	}
	public String getUpwd() {
		return upwd;
	}
	public void setUpwd(String upwd) {
		this.upwd = upwd;
	}
	
}
/**
 * 頁面跳轉控制
 * @author Xiaogf
 */
@Controller
@RequestMapping("/page")
public class PageController {

	/**
	 * 跳轉到登錄頁
	 * @return
	 */
	@RequestMapping("/login")
	public String toLogin(@RequestParam(required = false, defaultValue = "")String target,
						  HttpSession session, @CookieValue(required = false, value = "TOKEN")Cookie cookie) {
		if(StringUtils.isEmpty(target)) {
			//如果是直接從登錄系統登錄的,校驗成功後默認跳轉到主系統 sys1 的首頁
			target = "http://sys1.sso.com:8080/index";
		}
		// 如果是已登錄的用戶再次訪問登錄頁面,就要重定向
		if(cookie != null) {
			String value = cookie.getValue();
			User user = LoginCacheUtil.loginUser.get(value);
			if(user != null) {
				return "redirect:" + target;
			}
		}
		// 用於登錄成功後重定向地址
		session.setAttribute("target", target);
		return "login";
	}
}
@Controller
public class LoginController {

	@PostMapping("/login")
	public String doLogin(User user, HttpSession session, HttpServletResponse response) {
		// 校驗用戶名密碼
		if(user.getUname().equals("xiao")&&user.getUpwd().equals("123")) {
			// 保存用戶登錄信息
			String token = UUID.randomUUID().toString();
			System.out.println("login.token===" + token);
			Cookie cookie = new Cookie("TOKEN", token);
			//設置域名,實現數據共享
			cookie.setDomain("sso.com");
			// 把cookie寫到客戶端
			response.addCookie(cookie);
			LoginCacheUtil.loginUser.put(token, user);
		}else {
			session.setAttribute("msg", "用戶名或密碼錯誤");
			return "login";
		}
		//登錄信息校驗成功,重定向到原來的系統
		String targetUrl = (String) session.getAttribute("target");
		return "redirect:" + targetUrl;
	}
	
	/**
	 * 其他同域名的系統通過該接口獲取登錄用戶的信息
	 * @param token
	 * @return
	 */
	@RequestMapping("/info")
	@ResponseBody
	public ResponseEntity<User> getUserInfo(String token){
		if(!StringUtils.isEmpty(token)) {
			User user = LoginCacheUtil.loginUser.get(token);
			return ResponseEntity.ok(user);
		}else {
			return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);
		}
	}
}
public class LoginCacheUtil {
	//模擬系統的數據緩存,如 Redis 之類的
	public static Map<String, User> loginUser = new HashMap<>();
}

子系統

本例中 sys1,sys2,sys3 這幾個系統的頁面和登錄處理邏輯都是一樣的,注意地址和端口改改就行。這裏的 login 是 8080,sys1 是 8081,sys2 是 8082,sys3 是 8083
1)pom 文件同上
2)系統首頁界面 index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>sso-sys1</title>
</head>
<body>
	<h1>這裏是 sso-sys1 首頁</h1>
	<p th:unless="${session.loginUser==null}">
		<span style="color:deepskyblue;" th:text="${session.loginUser.uname}"></span> 已登錄
	</p>
	<a th:if="${session.loginUser==null}" href="http://login.sso.com:8080/page/login?target=http://sys1.sso.com:8081/index">登錄</a>
	<a th:unless="${session.loginUser==null}" href="/loginOut">退出</a>
</body>
</html>

登錄的路徑中,需要攜帶本系統的地址,以便登錄成功後可以跳轉回本系統首頁

3)控制層

@Controller
public class Sys1Controller {

	@Autowired
	private RestTemplate restTemplate;
	//獲取登錄用戶信息的 URL,就是訪問登錄系統的 info 接口
	private final String LOGIN_INFO_URL="http://login.sso.com:8080/info?token=";
	
	@RequestMapping("/index")
	public String toIndex(@CookieValue(required = false, value = "TOKEN")Cookie cookie, HttpSession session) {
		if(cookie != null) {
			//獲取cookie 中 TOKEN 的值
			String token = cookie.getValue();
			System.out.println("sys1.token===" + token);
			if(!StringUtils.isEmpty(token)) {
				//如果 TOKEN 中有值,則發送請求獲取登錄用戶的信息,並存到該系統的 session 緩存中
				Map object = restTemplate.getForObject(LOGIN_INFO_URL + token, Map.class);
				System.out.println("sys1.object===" + object);
				session.setAttribute("loginUser", object);
			}else {
				//如果 TOKEN 沒有值,代表沒有登錄或者已經退出,應該清除緩存中的登錄用戶信息
				session.setAttribute("loginUser", null);
			}
		}
		return "index";
	}
	
	@RequestMapping("/loginOut")
	public String loginOut(HttpSession session, HttpServletResponse response) {
		//清除session中用戶登錄信息
		session.setAttribute("loginUser", null);
		//清除cookie中 TOKEN 的值
		Cookie cookie = new Cookie("TOKEN", "null");
		cookie.setDomain("sso.com");
		response.addCookie(cookie);
		//重定向到該系統的首頁
		return "redirect:/index";
	}
}

4)啓動類需要加入一個 Bean

@SpringBootApplication
public class SsoSys1Application {

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

}

sys2 與 sys3 的 index.html 中地址和端口需要稍微改一下,其他一樣,這裏就不重複貼出來了。

測試

啓動登錄系統、sys1系統,sys2 系統和 sys3 系統,分別在不同標籤頁訪問 sys1.sso.com:8081/index 、sys2.sso.com:8082/index 、sys3.sso.com:8083/index ,
點擊登錄,都跳轉到了登錄系統 login.sso.com
當在其中一個系統登錄成功時,刷新另外一個系統,會發現也已經登錄了。
當在其中一個系統退出後,刷新另外一個系統,會發現也已經退出了。

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

發佈了89 篇原創文章 · 獲贊 47 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章