日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【身份认证及权限控制一】单点登录

發布時間:2024/10/5 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【身份认证及权限控制一】单点登录 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

官方介紹:單點登錄,簡稱為 SSO,是目前比較流行的企業業務整合的解決方案之一。 SSO的定義是在多個應用系統中,用戶只需要登錄一次就可以訪問所有相互信任的應用系統。是指在多系統應用群中登錄一個系統,便可在其他所有系統中得到授權而無需再次登錄,包括單點登錄與單點注銷兩部分。

一,單點登錄實現的原理?

以單個客戶端訪問單個服務端來講,以下圖為例!

1.1 會話機制

1.瀏覽器在第一次訪問Tomcat服務器的時候,Tomcat服務器會在服務端創建session對象,并存儲到map中,key是session的id,value是session對象本身。

2.在響應的時候會把session的id通過cookie的方式寫到客戶端瀏覽器中。

3.瀏覽器會在本地的目錄中把session的id寫入到本地的cookie中。

4.在后續的請求中,都會讀取本地的cookie中的內容,并在請求的時候帶上對應的cookie。

有了會話機制,登錄狀態就好明白了,我們假設瀏覽器第一次請求服務器需要輸入用戶名與密碼驗證身份,服務器拿到用戶名密碼去數據庫比對,正確的話說明當前持有這個會話的用戶是合法用戶,應該將這個會話標記為“已授權”或者“已登錄”等等之類的狀態,既然是會話的狀態,自然要保存在會話對象中,Tomcat在會話對象中設置登錄狀態如下:

HttpSession session = request.getSession();
session.setAttribute("isLogin", true);

用戶再次訪問時,tomcat在會話對象中查看登錄狀態:

HttpSession session = request.getSession(); session.getAttribute("isLogin");

實現了登錄狀態的瀏覽器請求服務器模型如下圖描述

每次請求受保護資源時都會檢查會話對象中的登錄狀態,只有isLogin=true的會話才能訪問,登錄機制因此而實現。

2、多系統的復雜性

隨著公司的發展,公司內部使用的系統越來越多,但是對于使用系統的員工來說不是個好事情。

?1.每個系統都需要記住對應的賬號和密碼,很多員工都是每個系統的賬戶和密碼都一樣的。

?2.如果同時要使用CRM系統,WMS系統,OA系統,用戶需要登錄三次。

?3.如果不使用了,還需要分別在三個系統中依次的注銷。
有沒有這樣的功能:我只需要登錄一次,公司里面所有的系統都可以使用,只需要注銷一次,所有的系統都退出登錄了,

如果能實現這樣的功能就非常好了!

單系統登錄解決方案的核心是cookie,cookie攜帶會話id在瀏覽器與服務器之間維護會話狀態。但cookie是有限制的,這個限制就是cookie的域(通常對應網站的域名),瀏覽器發送http請求時會自動攜帶與該域匹配的cookie,而不是所有cookie。什么意思呢?就是每個域名下面都有屬于自己的cookie域,如果是多個系統,那么就會有多個域名,而這些下面的cookie不能實現共享,只能各玩各的。

既然這樣,為什么不將web應用群中所有子系統的域名統一在一個頂級域名下,例如*.baidu.com,然后將它們的cookie域設置為baidu.com,這種做法理論上是可以的,甚至早期很多多系統登錄就采用這種同域名共享cookie的方式。

然而,可行并不代表好,共享cookie的方式存在眾多局限。首先,應用群域名得統一;其次,應用群各系統使用的技術(至少是web服務器)要相同,不然cookie的key值(tomcat為JSESSIONID)不同,無法維持會話,共享cookie的方式是無法實現跨語言技術平臺登錄的,比如java、php、.net系統之間;第三,cookie本身不安全。

3、單點登錄的實現過程

相比于單系統登錄,sso需要一個獨立的認證中心,只有認證中心能接受用戶的用戶名密碼等安全信息,其他系統不提供登錄入口,只接受認證中心的間接授權。間接授權通過令牌實現,sso認證中心驗證用戶的用戶名密碼沒問題,創建授權令牌,在接下來的跳轉過程中,授權令牌作為參數發送給各個子系統,子系統拿到令牌,即得到了授權,可以借此創建局部會話,局部會話登錄方式與單系統的登錄方式相同。這個過程,也就是單點登錄的原理,用下圖說明。

二、Http間的通信

sso認證中心與sso客戶端通信方式有多種,這里以簡單好用的HttpURLConnection為例,webService、rpc、restful api都可以。

1,HttpUrlConnection的簡單實用

在JDK的java.net包中已經提供了訪問HTTP協議的基本功能的類:HttpURLConnection。

HttpURLConnection是Java的標準類,它繼承自URLConnection,可用于向指定網站發送GET請求、POST請求。

具體代碼在下面的代碼實現步驟再詳細講解!、

三、單點登錄的實現步驟(語言描述)

1,客戶端操作

1.攔截客戶端的請求判斷是否有局部的session
2.1如果有局部的session,放行請求
2.2如果沒有局部session
? ?2.2.1請求中有攜帶token參數
? ??
? ? ? ? ? ? ?2.2.1.1如果有,使用HttpURLConnection發送請求校驗token是否有效
? ??
? ? ? ? ? ? ? ? ? ? ? ? ? ?2.2.1.1.1如果token有效,建立局部的session

2.2.1.1.2如果token無效,重定向到統一認證中心頁面進行登陸

? ? ? ? ? ? ?2.2.1.2如果沒有,重定向到統一認證中心頁面進行登陸

? 2.2.2請求中沒有攜帶token參數,重定向到統一認證中心頁面進行登陸

2、服務端操作

1.檢測客戶端在服務端是否已經登錄了(checkLogin方法)
1.1獲取session中的token
1.2如果token不為空,說明服務端已經登錄過了,此時重定向到客戶端的地址,并把token帶上

1.3如果token為空,跳轉到統一認證中心的的登錄頁面,并把redirectUrl放入到request域中
2.統一認證中心的登錄方法(login方法)
2.1判斷用戶提交的賬號密碼是否正確

2.2如果正確

? ?? ? ?2.2.1創建token(可以使用UUID,保證唯一就可以)

? ?? ? ?2.2.2把token放入到session中

?? ??? ?2.2.3這個token要知道有哪些客戶端登陸了,創建Map<String,List<String[]> clientMap;(為單點注銷做準備)

? ?SSOUtil.clientMap.put(token,new ArrayList());(把這些數據放入到數據庫中也是可以的,我們就做比較簡單的,模擬一下)

? ?? ? 2.2.4轉發到redirectUrl地址,把token帶上

2.3如果錯誤

轉發到login.jsp,還需要把redirectUrl參數放入到request域中
3.統一認證中心認證token方法(verify方法),返回值為String,貼@ResponseBody
3.1如果SSOUtil.clientMap.get(token)有數據clientList,說明token是有效的

? ?? ? ?3.1.1clientList把客戶端傳入的客戶端登出地址(clientLogOutUrl)和會話ID(jsessionid)保存到集合中

? ?? ? ?3.1.2返回true字符串

3.1如果SSOUtil.clientMap.get(token)為null,說明token是無效的,返回false字符串

四,單點注銷的實現步驟(語言描述)

1、客戶端操作

在登陸的按鈕鏈接寫上統一認證中心的登出方法即可.

? <a href="http://www.sso.com/logOut">退出</a>

2、服務端操作?

1,編寫logOut方法,調用session.invalidate() 2,創建session的監聽器,在session的監聽器的銷毀方法寫如下邏輯2.1,獲取session中的token2.2,根據token在SSOUtil.clientMap獲取所有客戶端的登出地址和會話id2.3,通過HttpUtil選項調用客戶端的登出方法3,將session監聽器注冊到web.xml中

五、手寫單點登錄的實現

1、在hosts文件中添加配置

127.0.0.1 www.zhongxin.com
127.0.0.1 www.jiudian.com
127.0.0.1 www.wuliu.com

?這樣做的目的是測試的時候可以明確的分辨出來每個系統。

2、創建三個web的springboot項目

sso_client1 酒店管理系統
sso_client2物流管理系統
sso_server統一認證中心
因為是在本機上測試,所以給酒店管理系統設置端口為8081,物流管理系統端口為8082,而統一認證中心的端口為8080。

這樣的話,訪問每個系統的路徑就是

酒店管理系統 http://www.jiudian.com:8081/main
物流管理系統 http://www.wuliu.com:8082/main
統一認證中心 http://www.zhongxin.com:8080/checkLogin
(1)子系統的代碼實現

首先寫第一個子系統(酒店管理系統),其實子系統的功能代碼都是一樣的,唯一不一樣的無非就是改一下端口這些最主要的區別,一個子系統寫好之后復制一份就是另一個子系統了。

配置sso.properties文件

這個配置文件的作用其實就是指定了統一認證中心的地址和本系統地址,為了后續到這個文件中直接取地址,而不用手寫了。

server-url-prefix=http://www.zhongxin.com:8080 client-host-url=http://www.jiudian.com:8081

添加SSOClientUtil工具類

這個工具類就是去sso.properties配置文件中拿地址,并且封裝了跳轉到統一認證中心的方法。

public class SSOClientUtil {private static Properties ssoProperties = new Properties();public static String SERVER_URL_PREFIX;//統一認證中心地址:http://www.sso.com:8443,在sso.properties配置public static String CLIENT_HOST_URL;//當前客戶端地址:http://www.crm.com:8088,在sso.properties配置static{try {ssoProperties.load(SSOClientUtil.class.getClassLoader().getResourceAsStream("sso.properties"));} catch (IOException e) {e.printStackTrace();}SERVER_URL_PREFIX = ssoProperties.getProperty("server-url-prefix");CLIENT_HOST_URL = ssoProperties.getProperty("client-host-url");}/*** 當客戶端請求被攔截,跳往統一認證中心,需要帶redirectUrl的參數,統一認證中心登錄后回調的地址* 通過Request獲取這次請求的地址 http://www.jiudian.com:8081/* * @param request* @return*/public static String getRedirectUrl(HttpServletRequest request){//獲取請求URLreturn CLIENT_HOST_URL+request.getServletPath();}/*** 根據request獲取跳轉到統一認證中心的地址 http://www.zhongxin.com:8080/checkLogin?redirectUrl=http://www.jiudian.com:8081/* 通過Response跳轉到指定的地址* @param request* @param response* @throws IOException*/public static void redirectToSSOURL(HttpServletRequest request,HttpServletResponse response) throws IOException {String redirectUrl = getRedirectUrl(request);StringBuilder url = new StringBuilder(50).append(SERVER_URL_PREFIX).append("/checkLogin?redirectUrl=").append(redirectUrl);//轉發到注冊中心response.sendRedirect(url.toString());}/*** 獲取客戶端的完整登出地址 http://www.jiudian.com:8081/logOut* @return*/public static String getClientLogOutUrl(){return CLIENT_HOST_URL+"/logOut";}/*** 獲取認證中心的登出地址 http://www.zhongxin.com:8080/logOut* @return*/public static String getServerLogOutUrl(){return SERVER_URL_PREFIX+"/logOut";} }

添加HttpUtil工具類

這個工具類的作用主要是幫我們封裝了發起瀏覽器的請求,跨域訪問,參數使用Map集合進行傳遞。

public class HttpUtil {/*** 模擬瀏覽器的請求* @param httpURL 發送請求的地址* @param params 請求參數* @return* @throws Exception*/public static String sendHttpRequest(String httpURL,Map<String,String> params) throws Exception{//建立URL連接對象URL url = new URL(httpURL);//創建連接HttpURLConnection conn = (HttpURLConnection) url.openConnection();//設置請求的方式(需要是大寫的)conn.setRequestMethod("POST");//設置需要輸出conn.setDoOutput(true);//判斷是否有參數.if(params!=null&&params.size()>0){StringBuilder sb = new StringBuilder();for(Entry<String,String> entry:params.entrySet()){sb.append("&").append(entry.getKey()).append("=").append(entry.getValue());}//sb.substring(1)去除最前面的&conn.getOutputStream().write(sb.substring(1).toString().getBytes("utf-8"));}//發送請求到服務器conn.connect();//獲取遠程響應的內容.String responseContent = StreamUtils.copyToString(conn.getInputStream(),Charset.forName("utf-8"));conn.disconnect();return responseContent;}/*** 模擬瀏覽器的請求* @param httpURL 發送請求的地址* @param jesssionId 會話Id* @return* @throws Exception*/public static void sendHttpRequest(String httpURL,String jesssionId) throws Exception{//建立URL連接對象URL url = new URL(httpURL);//創建連接HttpURLConnection conn = (HttpURLConnection) url.openConnection();//設置請求的方式(需要是大寫的)conn.setRequestMethod("POST");//設置需要輸出conn.setDoOutput(true);conn.addRequestProperty("Cookie","JSESSIONID="+jesssionId);//發送請求到服務器conn.connect();conn.getInputStream();conn.disconnect();} }

準備html頁面和controller跳轉方法

這一切都是在配置了thymeleaf模板引擎的前提下進行的。

就是在瀏覽器發起請求http://www.jiudian.com:8081/main可以跳到歡迎頁面

<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body> 歡迎進入一天一次酒店的管理系統 <a href="http://www.zhongxin.com:8080/logout">退出</a> </body> </html> @Controller public class TestController {@RequestMapping("/main")public String show(){return "index";} }

配置過濾器

當然,在沒有登錄的時候是不可以直接訪問歡迎頁面的,這里說明一下:登錄是在統一認證中心進行的!所以需要配置一個過濾器,在發起請求之后會先進到過濾器中。

在過濾器中一共做下面幾件事情:

判斷是否有局部會話,如果有,則放行,如果沒有,重定向到統一認證中心,檢查是否有其他的系統已經登錄過。
判斷地址欄中是否攜帶了token參數(這是在統一認證中心登錄之后重定向過來的請求,會帶上token),如果有token,那么向統一認證中心發起請求來判斷該token是否由統一認證中心產生的,如果是,則放行,如果不是,重定向到統一認證中心去登錄。
說明:

通過實現Filter接口,創建一個過濾器類,通過@WebFilter注解,注冊過濾器。
urlPatterns屬性代表需要被過濾的請求地址。filterName屬性代表過濾器名稱;
在SpringBoot應用啟動類中,添加@ServletComponentScan注解,表示項目啟動自動掃描Servlet組件。Filter屬于Servlet組件
引起注意的一點:重定向到統一認證中心的路徑是http://www.zhongxin.com:8080/checkLogin?redirectUrl=http://www.jiudian.com:8081/main這種格式的,就是前面是http請求,后面加上了redirectUrl參數,為本子系統的訪問路徑,因為把這個傳到認證中心之后,在認證中心登錄之后還要拿到這個參數(子系統訪問路徑)進行轉發回來。

看一下底層代碼:

?它是將認證中心的路徑和子系統的路徑做了一個拼接,然后response進行了重定向。

過濾器代碼

/*** 通過實現Filter接口,創建一個過濾器類* 通過@WebFilter注解,注冊過濾器。urlPatterns屬性代表需要被過濾的請求地址。filterName屬性代表過濾器名稱* 在SpringBoot應用啟動類中,添加@ServletComponentScan注解,表示項目啟動自動掃描Servlet組件。Filter屬于Servlet組件*/ @Component //加入tomcat容器 @WebFilter(urlPatterns = "/*",filterName = "ssoFilter") public class SSOClientFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {System.err.println("############進入了過濾器#############");HttpServletRequest req = (HttpServletRequest) request;HttpServletResponse res= (HttpServletResponse) response;HttpSession session = req.getSession();//1,判斷是否有局部的會話Boolean isLogin= (Boolean) session.getAttribute("isLogin");if(isLogin!=null && isLogin){//有局部會話,直接放行chain.doFilter(request,response);return;}//判斷地址欄中是否攜帶了token參數(這是在統一認證中心登錄之后重定向過來的請求,會帶上token)String token=req.getParameter("token");if(token!=null || token !=""){//token信息不為null,擁有令牌//判斷token信息是否由認證中心產生的//這里使用寫好的工具類發送http請求 SSOClientUtil.SERVER_URL_PREFIX是統一認證中心的IPString httpUrl=SSOClientUtil.SERVER_URL_PREFIX+"/verify";//參數Map<String,String> params=new HashMap<String, String>();params.put("token",token);//這里放入clientUrl和jsessionId這兩個參數是為了單點注銷做準備params.put("clientUrl",SSOClientUtil.getClientLogOutUrl());params.put("jsessionId",session.getId());try {//發送請求,server端(統一認證中心)會返回一個字符串String isVerify = HttpUtil.sendHttpRequest(httpUrl, params);if("true".equals(isVerify)){//如果返回的字符串是true,說明這個token是由認證中心產生的//創建局部的會話session.setAttribute("isLogin",true);//放行該次請求chain.doFilter(request,response);return;}} catch (Exception e) {e.printStackTrace();}}//2,沒有局部會話,重定向到統一認證中心,檢查是否有其他的系統已經登錄過//http://www.zhongxin.com:8080/checkLogin?redirectUrl=http://www.jiudian.com:8081SSOClientUtil.redirectToSSOURL(req,res);}@Overridepublic void destroy() {} }

?

到這里子系統的代碼已經完成了,接下來開始寫統一認證中心。

(2)統一認證中心的代碼實現

首先項目要配置好thymeleaf模板引擎,這都不用說了吧?

然后先準備一個登錄頁面。表單項redirectUrl是隱藏的,是子系統的路徑,是表單提交的一個參數,因為在登錄方法中進行驗證,如果賬號密碼成功之后,還要拿到這個路徑進行重定向回來。

<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head><meta charset="UTF-8"><title>登錄</title><script src="js/jquery.1.12.4.min.js"></script> </head> <body> <h1>請登錄</h1> <!--<span id="span" th:text="${redirectUrl}"></span>--> <form id="form" action="/login" method="post"><input type="hidden" th:value="${redirectUrl}" name="redirectUrl">賬號:<input type="text" name="username"><br>密碼:<input type="password" name="password"><br><input type="submit" value="登錄"> </form> </body> </html>

模擬數據庫

這里沒有連接數據庫,只是使用集合來存儲數據來模擬一下。

其實需要兩張表,一張是存放token令牌的表T_TOKEN,另一張是存放統計注冊過的子系統信息的表T_CLIENT_INFO(token為id,其他字段為clientUrl(子系統訪問路徑),jsessionid(session的id),這里使用集合表示了)

先建一個實體類,裝載子系統的信息。

public class ClientInfo {private String clientUrl;private String jsessionid;}

DataBaseUtil類,連個集合(代表兩張表)

public class DataBaseUtil {//創建一個存放token令牌信息的集合public static Set<String> T_TOKEN=new HashSet<String>();//創建一個統計注冊過的子系統信息的集合public static Map<String, List<ClientInfo>> T_CLIENT_INFO=new HashMap<String, List<ClientInfo>>(); }

添加HttpUtil工具類

因為如果登錄成功之后要重定向到子系統,所以需要這個工具類來進行跨域請求。

這個類上面已經給過了,略過。

在controller進行處理(中心內容)

在這個controller中要做下面幾件事:

檢查是否登錄,判斷是否有全局會話,如果沒有,跳轉到統一認證中心的登錄頁面,也就是本系統的登錄頁面,如果有,
1.取出令牌信息,重定向到子系統,把令牌帶上。

?2. 登錄功能,檢查賬號密碼是否匹配, 如果匹配,創建令牌信息,創建全局會話,把令牌信息放到會話中,重定向`redirectUrl`子系統,并把令牌信息帶上;如果不匹配,則重新回到登錄頁面,還需要把`redirectUrl`放到`request`域中。
? ? 3. 校驗`token`是否由統一認證中心產生的,如果是,則返回`true`字符串,并記錄客戶端的登出地址,記錄登出地址是為了單點注銷做準備的。
? ? 4. 單點注銷。

@Controller public class TestController {@RequestMapping("/checkLogin")public String show(String redirectUrl, HttpSession session, Model model){//1,判斷是否有全局的會話String token= (String) session.getAttribute("token");if(token==null || token==""){//表示沒有全局會話//跳轉到統一認證中心的登錄頁面,也就是本系統的登錄頁面model.addAttribute("redirectUrl",redirectUrl);return "login";}else{//有全局會話//取出令牌信息,重定向到redirectUrl,把令牌帶上return "redirect:"+redirectUrl+"?token="+token;}}/*** 登錄功能*/@RequestMapping("/login")public String login(String username,String password,String redirectUrl,HttpSession session,Model model){if("admin".equals(username)&&"123".equals(password)){//賬號密碼匹配//1,創建令牌信息String token= UUID.randomUUID().toString();//2,創建全局會話,把令牌信息放到會話中session.setAttribute("token",token);//3,需要把令牌放到數據庫中,這里不連數據庫,創建list模擬一下DataBaseUtil.T_TOKEN.add(token);//4,重定向redirectUrl,并把令牌信息帶上 http://www.jiudian.com:8081/main?token=//參數可存放到model,可以直接重定向帶過去return "redirect:"+redirectUrl+"?token="+token;}else{//賬號密碼錯誤,重新回到登錄頁面,還需要把redirectUrl放到request域中model.addAttribute("redirectUrl",redirectUrl);return "login";}}/*** 校驗token是否由統一認證中心產生的*/@RequestMapping("/verify")@ResponseBodypublic String verify(String token,String clientUrl,String jsessionId){if(DataBaseUtil.T_TOKEN.contains(token)){//記錄客戶端的登出地址List<ClientInfo> clientInfoList = DataBaseUtil.T_CLIENT_INFO.get("token");if(clientInfoList==null){clientInfoList=new ArrayList<ClientInfo>();DataBaseUtil.T_CLIENT_INFO.put(token,clientInfoList);}ClientInfo clientInfo=new ClientInfo();clientInfo.setClientUrl(clientUrl);clientInfo.setJsessionid(jsessionId);clientInfoList.add(clientInfo);//說明令牌有效,返回truereturn "true";}return "false";}/*** 單點注銷*/@RequestMapping("logout")@ResponseBodypublic String logout(HttpSession session){/*** 銷毀全局會話* session.invalidate()方法會執行session監聽器的銷毀方法(什么是session監聽器?)*/session.invalidate();return "退出成功!";} }

單點注銷

單點注銷其實就是在子系統的退出按鈕上添加路徑為http://www.zhongxin.com:8080/logout即可,然后在統一認證中心進行銷毀全局會話的操作。

通過session.invalidate()進行銷毀全局會話,該方法會執行session監聽器的銷毀方法。至于什么是監聽器,上網查吧!

創建一個session會話監聽器

該監聽類繼承HttpSessionListener實現兩個方法,sessionDestroyed方法是sesison在銷毀的時候執行的動作。

springboot項目加入session監聽器和過濾器,都要加上@WebListener注解,在啟動類上都要加上@ServletComponentScan(com.aaa)注解。
?

//session監聽 @WebListener //加到tomcat容器中 springboot項目加入session監聽器和過濾器,都要加上@WebListener注解,在啟動類上都要加上@ServletComponentScan注解 public class MySessionListener implements HttpSessionListener {@Overridepublic void sessionCreated(HttpSessionEvent se) {}/*** session銷毀監聽* @param se*/@Overridepublic void sessionDestroyed(HttpSessionEvent se) {HttpSession session = se.getSession();String token= (String) session.getAttribute("token");//刪除token表中的數據DataBaseUtil.T_TOKEN.remove(token);List<ClientInfo> clientInfoList = DataBaseUtil.T_CLIENT_INFO.remove(token);try {//獲取出注冊的子系統,依次調用子系統登出的方法,也就是把子系統的session全部清除掉for(ClientInfo clientInfo:clientInfoList) {HttpUtil.sendHttpRequest(clientInfo.getClientUrl(), clientInfo.getJsessionid());}} catch (Exception e) {e.printStackTrace();}} }

?

然后單點登錄就搞定了。

補充:其實上面的單點注銷并沒有實現,不清楚哪里除了問題,不過后來通過一個簡單的方法實現了,就是在session監聽銷毀中的HttpUtil.sendHttpRequest的url路徑參數的進行字符串拼接然后改成了http:www.jiudian.com:8081/go這樣的路徑,然后分別在子系統的controller中添加go的映射方法,把session的isLogin設為false即可。雖然有點兒low,但是實現了!

六、手寫單點登錄的效果展示

首先把三個項目都啟動起來。

然后先訪問酒店管理系統,在瀏覽器發起請求http://www.jiudian.com:8081/main

然后會跳轉到統一認證中心的登錄頁面

?

然后訪問物流管理系統,在瀏覽器發起請求http://www.wuliu.com:8082/main

它還是會跳轉到統一認證中心的登錄頁面

然后,重點來了,在酒店管理系統的登錄下輸入賬號密碼,進行登錄

如果錯誤會重新返回登錄頁面,這里登錄成功

然后會重定向到子系統酒店的歡迎頁面

?

此時再去訪問物流管理系統時,你會發現不用登錄就直接進到物流管理系統的歡迎頁了!

單點注銷就不演示了,一個子系統進行退出之后,在統一認證中心銷毀了全局會話信息,然后所有子系統都退出了!

?

七、知識點

1,@Slf4j日志

該日志是屬于lombok插件的,安裝lombok插件,或者在maven中并導入lombok依賴。

<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.16.10</version><scope>provided</scope></dependency>

然后就可以使用了!

使用方法:在類上面加上注解@Slf4j,然后通過在代碼中log.info()來打印日志。

2、springboot配置session監聽器

session監聽器由session對象調用invalidate()方法而調用,session監聽器監聽session的創建和銷毀。

使用步驟:

在需要銷毀session的地方寫
?

session.invalidate();

?然后就會調用session監聽器的銷毀方法,如果一個客戶端一登錄進來記錄了session,那么會第一個就是進入session監聽器的創建方法。

session監聽器如何配置?

springboot項目加入session監聽器和過濾器,都要加上@WebListener注解,在啟動類上都要加上@ServletComponentScan(com.aaa)注解。
@ServletComponentScan注解一定要加包名進行掃描,否則掃描不到該監聽器,具體掃描機制待以后研究!(都是經驗,前輩趟過的路就不要走第二次了)
?

@WebListener public class MySessionListener implements HttpSessionListener {@Overridepublic void sessionCreated(HttpSessionEvent se) {}@Overridepublic void sessionDestroyed(HttpSessionEvent se) { } }

3、重定向發起http請求的方式

  • response.sendRedirect重定向
  • return "redirect"重定向

response重定向的方式,舉個例子

public void redirectToSSOURL(HttpServletRequest request,HttpServletResponse response) {String redirectUrl = getRedirectUrl(request);//這句代碼忽略,只是舉個例子而已,不要管這個參數StringBuilder url = new StringBuilder(50).append("http://www.zhongxin.com:8080").append("/checkLogin?redirectUrl=").append(redirectUrl);//轉發到注冊中心response.sendRedirect(url.toString());}

這樣重定向的路徑就是http://www.zhongxin.com:8080/checkLogin?redirectUrl=XXX

return "redirect"重定向方式,再舉個例子

@RequestMapping("/checkLogin")public String show(){String redirectUrl="http://www.jiudian.com:8081";String token="test"return "redirect:"+redirectUrl+"?token="+token;}}

這樣重定向的路徑就是http://www.jiudian.com:8081?token=test

注意:只有重定向才能跨域發起請求,而轉發只能在本系統進行轉發,不能跨域。

八,結束語

真正企業級的單點登錄肯定不會像上面那樣實現,上面只是手寫實現了單點登錄,真正給企業部署單點登錄的話就需要很多復雜性的內容了,而且還會考慮到更多安全性的問題。
原文鏈接:https://blog.csdn.net/weixin_44001965/article/details/103365351

總結

以上是生活随笔為你收集整理的【身份认证及权限控制一】单点登录的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。