SpringBoot如何實(shí)現(xiàn)同域SSO(單點(diǎn)登錄)
單點(diǎn)登錄,其實(shí)看起來(lái)不是很復(fù)雜,只是細(xì)節(jié)上的處理,單點(diǎn)區(qū)分有三種
- 同域SSO
- 同父域SSO
- 跨域的SSO
如何實(shí)現(xiàn)同域SSO?
個(gè)人理解:當(dāng)用戶(hù)登錄訪(fǎng)問(wèn)demo1.lzmvlog.top時(shí),同時(shí)具有訪(fǎng)問(wèn)demo2.lzmvlog.top的能力,即認(rèn)證完成一次,可以訪(fǎng)問(wèn)所有系統(tǒng)。
實(shí)現(xiàn)方式:可以采用Cookie實(shí)現(xiàn),即用戶(hù)在訪(fǎng)問(wèn)一個(gè)系統(tǒng)時(shí),攜帶認(rèn)證頒發(fā)的信息,系統(tǒng)響應(yīng)是否具有訪(fǎng)問(wèn)資格,否則跳轉(zhuǎn)認(rèn)證,也可以采用Session,即Session共享,校驗(yàn)訪(fǎng)問(wèn)用戶(hù)是否具有有效的信息,提供訪(fǎng)問(wèn)資格
代碼實(shí)現(xiàn)
依賴(lài)
<!--spring-data-jpa-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
配置
server:
port: 8090
spring:
application:
name: authority
datasource:
url: jdbc:mysql://127.0.0.1:3306/SSO?useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
當(dāng)用戶(hù)訪(fǎng)問(wèn)除登錄界面時(shí),都需要提前認(rèn)證,認(rèn)證完成之后需要跳轉(zhuǎn)到之前訪(fǎng)問(wèn)的路徑上,并提供訪(fǎng)問(wèn)別的系統(tǒng)的權(quán)限。
實(shí)現(xiàn)邏輯,當(dāng)用戶(hù)訪(fǎng)問(wèn)任何路徑時(shí),都需要通過(guò)攔截器的校驗(yàn),確認(rèn)擁有訪(fǎng)問(wèn)的權(quán)限,才能放行通過(guò),不具有訪(fǎng)問(wèn)權(quán)限的,重定向到 登錄界面,并保存原有訪(fǎng)問(wèn)的頁(yè)面路徑,驗(yàn)證成功的時(shí)候跳轉(zhuǎn)到原有頁(yè)面
控制器
@Controller
public class IndexController {
@Autowired
UserRepository userRepository;
/**
* 將要跳轉(zhuǎn)的路徑
*/
public String url;
/**
* 登錄界面
*
* @return
*/
@GetMapping("/index")
public String index() {
return "index";
}
/**
* 登錄界面
*
* @return
*/
@GetMapping("/")
public String index1() {
return "index";
}
/**
* 登錄請(qǐng)求接口
*
* @param username 賬號(hào)
* @param password 密碼
* @param response
* @return
*/
@PostMapping("login")
public String login(String username, String password, HttpServletResponse response) {
// 用戶(hù)登錄
boolean exists = userRepository.exists(Example.of(new User()
.setUsername(username)
.setPassword(password)));
if (exists) {
Cookie cookie = new Cookie("username", username);
response.addCookie(cookie);
// 如果正常訪(fǎng)問(wèn)即跳轉(zhuǎn)到正常頁(yè)面
if (StringUtils.isEmpty(url)) {
return "demo1";
}
// 如果之前存在訪(fǎng)問(wèn)的頁(yè)面,認(rèn)證完成即跳轉(zhuǎn)會(huì)原有的頁(yè)面
return url;
}
return "index";
}
/**
* 跳轉(zhuǎn)到 demo2
*
* @return
*/
@GetMapping("demo2")
public String demo2() {
return "demo2";
}
/**
* 跳轉(zhuǎn)到 demo1
*
* @return
*/
@GetMappi=ng("demo1")
public String demo1() {
return "demo1";
}
}
攔截器實(shí)現(xiàn)
@Component
public class CookieHandlerInterceptor implements HandlerInterceptor {
@Autowired
UserRepository userRepository;
@Autowired
IndexController indexController;
/**
* 執(zhí)行方法之前
*
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 獲取當(dāng)前請(qǐng)求得路徑 如果不是正常得登錄界面請(qǐng)求 登錄成功之后需要跳轉(zhuǎn)到原來(lái)請(qǐng)求得界面上
String servletPath = request.getServletPath();
// 對(duì)不需要攔截得路徑進(jìn)行放行
if ("/index".equals(servletPath) || "/".equals(servletPath) || "/login".equals(servletPath)) {
return true;
}
if (!"/index".equals(servletPath) || !"/".equals(servletPath)) {
indexController.url = servletPath;
}
Cookie[] cookies = request.getCookies();
boolean exists = false;
if (cookies != null) {
for (Cookie cookie : cookies) {
String value = cookie.getValue();
if (!StringUtils.isEmpty(value)) {
exists = userRepository.exists(Example.of(new User()
.setUsername(value)));
}
}
}
if (exists) {
return true;
} else {
response.sendRedirect("/index");
}
return false;
}
}
在SpringBoot2.x之后不能生效,需要將攔截器添加到攔截器鏈路中,即:
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
/**
* Session 攔截處理器
*/
@Autowired
private CookieHandlerInterceptor cookieHandlerInterceptor;
/**
* 添加攔截器
*
* @param registry
*/
@Override
protected void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(this.cookieHandlerInterceptor).addPathPatterns("/**");
super.addInterceptors(registry);
}
}
其實(shí)攔截器還有第二種實(shí)現(xiàn)方式,即通過(guò)Filter接口實(shí)現(xiàn)
@Component
public class CookieFilter extends OncePerRequestFilter {
@Autowired
UserRepository userRepository;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
// 獲取當(dāng)前請(qǐng)求得路徑 如果不是正常得登錄界面請(qǐng)求 登錄成功之后需要跳轉(zhuǎn)到原來(lái)請(qǐng)求得界面上
String servletPath = request.getServletPath();
IndexController indexController = new IndexController();
// 對(duì)不需要攔截得路徑進(jìn)行放行
if ("/index".equals(servletPath) || "/".equals(servletPath) || "/login".equals(servletPath)) {
filterChain.doFilter(request, response);
}
if (!"/index".equals(servletPath) || !"/".equals(servletPath)) {
indexController.url = servletPath;
}
Cookie[] cookies = request.getCookies();
boolean exists = false;
if (cookies != null) {
for (Cookie cookie : cookies) {
String value = cookie.getValue();
if (!StringUtils.isEmpty(value)) {
exists = userRepository.exists(Example.of(new User()
.setUsername(value)));
}
}
}
if (exists) {
filterChain.doFilter(request, response);
} else {
response.sendRedirect("/");
}
}
}
其實(shí)也可以采用Session的方式實(shí)現(xiàn),采用共享Session的方式,我這里只是簡(jiǎn)單的實(shí)現(xiàn)一下,其實(shí)在認(rèn)證時(shí)可以結(jié)合SpringSecurity或者Shiro安全框架去整合JWT以保證信息的安全
界面
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登錄</title>
</head>
<body>
<div align="center">
<h1>請(qǐng)登錄</h1>
<form action="/login" method="post">
<span>賬號(hào):</span><input name="username" type="text" value="zhang"><br>
<span>密碼:</span><input name="password" type="password" value="123456"><br>
<button type="submit" style="margin: 10px 0">登錄</button>
</form>
</div>
</body>
</html>
demo1.html和demo2.html只需要坐一下簡(jiǎn)單的區(qū)分,知道是哪個(gè)頁(yè)面就行了
同域SSO其實(shí)不是很復(fù)雜,只是了解一下整個(gè)訪(fǎng)問(wèn)的過(guò)程,和需要做的一些限制即可,后續(xù)看看做后面兩種的實(shí)現(xiàn)
即同父域SSO和跨域SSO
以上就是SpringBoot如何實(shí)現(xiàn)同域SSO(單點(diǎn)登錄)的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot 實(shí)現(xiàn)同域SSO的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
java中 spring 定時(shí)任務(wù) 實(shí)現(xiàn)代碼
java中 spring 定時(shí)任務(wù) 實(shí)現(xiàn)代碼,需要的朋友可以參考一下2013-03-03
spring redis 如何實(shí)現(xiàn)模糊查找key
這篇文章主要介紹了spring redis 如何實(shí)現(xiàn)模糊查找key的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08
springboot+swagger2.10.5+mybatis-plus 入門(mén)詳解
這篇文章主要介紹了springboot+swagger2.10.5+mybatis-plus 入門(mén),本文通過(guò)實(shí)例圖文相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12
BeanUtils.copyProperties復(fù)制對(duì)象結(jié)果為空的原因分析
這篇文章主要介紹了BeanUtils.copyProperties復(fù)制對(duì)象結(jié)果為空的原因分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06
Java創(chuàng)建多線(xiàn)程服務(wù)器流程
這篇文章主要介紹了Java創(chuàng)建多線(xiàn)程服務(wù)器流程,以下實(shí)例演示了如何使用Socket類(lèi)的accept()方法和ServerSocket類(lèi)的MultiThreadServer(socketname)方法來(lái)實(shí)現(xiàn)多線(xiàn)程服務(wù)器程序2023-05-05
SpringBoot整合SSO(single sign on)單點(diǎn)登錄
這篇文章主要介紹了SpringBoot整合SSO(single sign on)單點(diǎn)登錄,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06
redis發(fā)布訂閱Java代碼實(shí)現(xiàn)過(guò)程解析
這篇文章主要介紹了redis發(fā)布訂閱Java代碼實(shí)現(xiàn)過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09

