1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        redis系列——基于Redis實現(xiàn)的單點登錄(Demo)

        共 16219字,需瀏覽 33分鐘

         ·

        2020-10-24 05:31

        點擊上方藍色字體,選擇“標星公眾號”

        優(yōu)質文章,第一時間送達

        66套java從入門到精通實戰(zhàn)課程分享

        一、SSO技術簡介

        1、基本介紹

        ? ??? ??目前的企業(yè)應用環(huán)境中,往往有很多的應用系統(tǒng),如辦公自動化(OA)系統(tǒng),財務管理系統(tǒng),檔案管理系統(tǒng),信息查詢系統(tǒng)等等。這些應用系統(tǒng)服務于企業(yè)的信息化建設,為企業(yè)帶來了很好的效益。但是,用戶在使用這些應用系統(tǒng)時,并不方便。用戶每次使用系統(tǒng),都必須輸入用戶名稱和用戶密碼,進行身份驗證;而且,應用系統(tǒng)不同,用戶賬號就不同,用戶必須同時牢記多套用戶名稱和用戶密碼。特別是對于應用系統(tǒng)數目較多,用戶數目也很多的企業(yè),這個問題尤為突出。問題的原因并不是系統(tǒng)開發(fā)出現(xiàn)失誤,而是缺少整體規(guī)劃,缺乏統(tǒng)一的用戶登錄平臺。

        ? ??? ? SSO(Single Sign-On,單點登錄)是身份管理中的一部分。SSO的一種較為通俗的定義是:SSO是在多個應用系統(tǒng)中,用戶只需要登錄一次就可以訪問所有相互信任的應用系統(tǒng)。它包括可以將這次主要的登錄映射到其他應用中用于同一個用戶的登錄的機制。它是目前比較流行的企業(yè)業(yè)務整合的解決方案之一。

        2、SSO解決的問題

        ? ? ? ? 我們在做SSO之前首先要明白為什么要有單點登錄,即SSO在解決什么問題?那么我們先來看一下傳統(tǒng)的登錄實現(xiàn)方式:

        以上就是傳統(tǒng)的登錄實現(xiàn)方式,但是在并發(fā)量高的情況下呢?比如現(xiàn)在有 2000~3000 的并發(fā),這時一個tomcat 不能滿足業(yè)務需求,需要做集群。如下:

        那么現(xiàn)在就會出現(xiàn)Session共享的問題(tomcat做集群配置session復制。如果集群中節(jié)點很多,會形成網絡風暴。推薦節(jié)點數量不要超過5個)。此外在分布式架構中,我們會把系統(tǒng)拆分成多個子系統(tǒng),在這些子系統(tǒng)之間進行跳轉時也會出現(xiàn)session不能共享的問題(和上述類似)。

        ? ? ? ? 上述這些情況正是SSO要解決的問題!

        3、使用SSO的好處

        • 方便用戶

        ? ??? ??用戶使用應用系統(tǒng)時,能夠一次登錄,多次使用。用戶不再需要每次輸入用戶名稱和用戶密碼,也不需要牢記多套用戶名稱和用戶密碼。單點登錄平臺能夠改善用戶使用應用系統(tǒng)的體驗。

        • 方便管理員

        ? ??? ??系統(tǒng)管理員只需要維護一套統(tǒng)一的用戶賬號,方便、簡單。相比之下,系統(tǒng)管理員以前需要管理很多套的用戶賬號。每一個應用系統(tǒng)就有一套用戶賬號,不僅給管理上帶來不方便,而且,也容易出現(xiàn)管理漏洞。

        • 簡化應用系統(tǒng)開發(fā)

        ? ??? ??開發(fā)新的應用系統(tǒng)時,可以直接使用單點登錄平臺的用戶認證服務,簡化開發(fā)流程。單點登錄平臺通過提供統(tǒng)一的認證平臺,實現(xiàn)單點登錄。因此,應用系統(tǒng)并不需要開發(fā)用戶認證程序。

        4、實現(xiàn)SSO的技術

        • 基于cookies實現(xiàn)

        ? ??? ??需要注意如下幾點:如果是基于兩個域名之間傳遞sessionid的方法可能在windows中成立,在unix&linux中可能會出現(xiàn)問題;可以基于數據庫實現(xiàn);在安全性方面可能會作更多的考慮。另外,關于跨域問題,雖然cookies本身不跨域,但可以利用它實現(xiàn)跨域的SSO。

        • Broker-based(基于經紀人)

        ? ??? ??例如Kerberos等,這種技術的特點就是,有一個集中的認證和用戶帳號管理的服務器。經紀人給被用于進一步請求的電子的身份存取。中央數據庫的使用減少了管理的代價,并為認證提供一個公共和獨立的”第三方”。例如Kerberos、Sesame、IBM KryptoKnight(憑證庫思想)等。

        • Agent-based(基于代理人)

        ? ??? ??在這種解決方案中,有一個自動地為不同的應用程序認證用戶身份的代理程序。這個代理程序需要設計有不同的功能。比如, 它可以使用口令表或加密密鑰來自動地將認證的負擔從用戶移開。代理人被放在服務器上面,在服務器的認證系統(tǒng)和客戶端認證方法之間充當一個”翻譯”。例如SSH等。

        • Token-based

        ? ??? ??例如SecurID、WebID;現(xiàn)在被廣泛使用的口令認證,比如FTP,郵件服務器的登錄認證,這是一種簡單易用的方式,實現(xiàn)一個口令在多種應用當中使用。

        • 基于安全斷言標記語言(SAML)實現(xiàn)

        ? ??? ? SAML(Security Assertion Markup Language,安全斷言標記語言)的出現(xiàn)大大簡化了SSO,并被OASIS批準為SSO的執(zhí)行標準。開源組織OpenSAML 實現(xiàn)了 SAML 規(guī)范,可參考http://www.opensaml.org/。

        二、SSO產品介紹

        1、SUN SSO技術

        1.SUM SSO介紹

        ? ??? ? SUN SSO技術是Sun Java System Access Manager產品中的一個組成部分。

        ? ??? ? Sun 的新身份管理產品包括Sun Java System Identity Manager、Sun Java System Directory Server Enterprise Edition 和 Sun Java System Access Manager,以上三者為Sun Java Identity Management Suite (身份識別管理套件)的組成部分,它們與Sun Java Application Platform Suite、Sun Java Availability Suite、Sun Java Communications Suite、Sun Java Web Infrastructure Suite組成Java ES。具有革新意義的這一系列產品提供端到端身份管理,同時可與 60 多種第三方資源和技術實現(xiàn)互操作,集成產品可以從SUN公司網站下載,一般以Agent軟件方式提供,是業(yè)內集成程序最高、最為開放的身份管理解決方案之一。

        ? ??? ??在Sun 的新身份管理產品中,Sun Java System Access Manager是基中的一個重要組成部分,Java Access Manager基于J2EE架構,采用標準的API,可擴展性強,具有高可靠性和高可用性,應用是部署在Servlets容器中的,支持分布式,容易部署且有較低的TCO。通過使用集中驗證點、其于角色的訪問控制以及 SSO,Sun Java System Access Manager 為所有基于 Web 的應用程序提供了一個可伸縮的安全模型。它簡化了信息交換和交易,同時能保護隱私及重要身份信息的安全。

        2.SUN SSO 實現(xiàn)原理

        ? ??? ? SSO的核心在于統(tǒng)一用戶認證,登錄、認證請求通過IDENTITY SERVER服務器完成,然后分發(fā)到相應應用。SUN SSO是java Access Manager的一個組成部分,SSO基于Cookie實現(xiàn)解釋如下:

        (1)Policy Agent on Web or Application Server intercepts resource requests and enforces access control;

        (2)Client is issued SSO token containing information for session Validation with Session service.

        (3)SSO token has no content- just a long random string used as a handle.

        (4)Web-based applications use browser session cookies or URL rewriting to issue SSO token.

        (5)Non Web applications use the SSO API(Java/c) to obtain the SSO token to validate the users identity.

        3.SUN SSO 的應用

        ? ??? ??這里說的應用是指Sun Java System Access Manager的應用。成功應用例子很多,包括德國電信等公司的應用,國內也有大量高校在使用,也有相當多的其它行業(yè)的應用。

        2、CAS技術

        1.CAS 背景介紹

        ? ??? ? CAS(Central Authentication Service),是耶魯大學開發(fā)的單點登錄系統(tǒng)(SSO,single sign-on),應用廣泛,具有獨立于平臺的,易于理解,支持代理功能。CAS系統(tǒng)在各個大學如耶魯大學、加州大學、劍橋大學、香港科技大學等得到應用。

        ? ??? ? Spring Framework的Acegi安全系統(tǒng)支持CAS,并提供了易于使用的方案。Acegi安全系統(tǒng),是一個用于Spring Framework的安全框架,能夠和目前流行的Web容器無縫集成。它使用了Spring的方式提供了安全和認證安全服務,包括使用Bean Context,攔截器和面向接口的編程方式。因此,Acegi安全系統(tǒng)能夠輕松地適用于復雜的安全需求。Acegi安全系統(tǒng)在國內外得到了廣泛的應用,有著良好的社區(qū)環(huán)境。

        2.CAS 的設計目標

        • 為多個Web應用提供單點登錄基礎設施,同時可以為非Web應用但擁有Web前端的功能服務提供單點登錄的功能;

        • 簡化應用認證用戶身份的流程;

        • 將用戶身份認證集中于單一的Web應用,讓用戶簡化他們的密碼管理,從而提高安全性;而且,當應用需要修改身份驗證的業(yè)務邏輯時,不需要到處修改代碼。

        3.CAS 的實現(xiàn)原理

        ? ??? ? CAS(Central Authentication Server)被設計成一個獨立的Web應用。CAS創(chuàng)建一個位數很長的隨機數(ticket)。CAS把這個ticket和成功登錄的用戶以及用戶要訪問的service聯(lián)系起來。例如,如果用戶peon重定向自service S,CAS創(chuàng)建ticket T,這個ticket T允許peon訪問service S。這個ticket是個一次性的憑證;它僅僅用于peon和僅僅用于service S,并且只能使用一次,使用之后馬上會過期,即ticket通過驗證,CAS立即刪除該ticket,使它以后不能再使用。這樣可以保證其安全性。

        ? ??? ??關于ST,在取一個ST時,即使用deleteTicket(ticketId)同時將一次性的ST刪除;而對于TGT或PT,則通過resetTimer(ticketId)以更新TGT或PT的時間。在CAS服務端返回的ST中只能得出用戶名。

        三、實現(xiàn)單點登錄系統(tǒng)

        1、SSO業(yè)務流程

        2、SSO系統(tǒng)創(chuàng)建

        ? ? ? ? 首先我們來創(chuàng)建SSO的Maven工程,添加依賴如下:


        ????
        ????
        ????????org.springframework
        ????????spring-context
        ????

        ????
        ????????org.springframework
        ????????spring-beans
        ????

        ????
        ????????org.springframework
        ????????spring-webmvc
        ????

        ????
        ????????org.springframework
        ????????spring-jdbc
        ????

        ????
        ????????org.springframework
        ????????spring-aspects
        ????

        ????
        ????????org.springframework
        ????????spring-context-support
        ????

        ????
        ????????javax.servlet
        ????????servlet-api
        ????????provided
        ????

        ????
        ????????javax.servlet
        ????????jsp-api
        ????????provided
        ????

        ????
        ????
        ????????redis.clients
        ????????jedis
        ????




        ????
        ????????
        ????????????org.apache.tomcat.maven
        ????????????tomcat7-maven-plugin
        ????????????
        ????????????????8084
        ????????????????/
        ????????????

        ????????

        ????

        ? ? ? ? 我們這里的SSO系統(tǒng)主要提供兩個功能模塊,一個是用戶的注冊功能,另一個就是用戶登錄相關的功能。下面我們就來分別實現(xiàn)這兩個模塊。因為我們這里采用了mybatis框架,并且持久化層都是簡單的增刪改查操作,所以這里就直接使用Mybatis的逆向工程來生成Dao的代碼了。

        1.用戶注冊

        1)數據校驗接口

        ? ??? ? Controller只是發(fā)布服務。接收三個參數,一個是要校驗的數據,一個數據類型,一個是callback。調用Service校驗。返回json數據。需要支持jsonp,需要判斷callback。

        @RequestMapping("/check/{param}/{type}")
        @ResponseBody
        public?Object?checkData(
        ????????@PathVariable?String?param,
        ????????@PathVariable?Integer?type,
        ????????String?callback){
        ????try?{
        ????????ResultObject?result?=?registerService.checkData(param,?type);
        ????????if(StringUtils.isNotBlank(callback)){
        ????????????//請求為jsonp,需要支持
        ????????????MappingJacksonValue?mappingJacksonValue?=?new?MappingJacksonValue(result);
        ????????????mappingJacksonValue.setJsonpFunction(callback);
        ????????????return?mappingJacksonValue;
        ????????}
        ????????return?result;
        ????}?catch?(Exception?e)?{
        ????????e.printStackTrace();
        ????????return?ResultObject.build(500,?"數據校驗失敗");
        ????}
        }

        ? ??? ? Service接收兩個參數,一個是要校驗的數據,一個是數據類型。根據不同的數據類型生成不同的查詢條件,到user表中進行查詢如果查詢到結果返回false,查詢結果為空返回true。

        public?ResultObject?checkData(String?param,?int?type)?{
        ????//根據數據類型檢測數據
        ????TbUserExample?example?=?new?TbUserExample();
        ????Criteria?criteria?=?example.createCriteria();
        ????//1、2、3分別代表username,phone,email-->都不可重復
        ????if(1==type){
        ????????criteria.andUsernameEqualTo(param);
        ????}else?if?(2==type)?{
        ????????criteria.andPhoneEqualTo(param);
        ????}else?if?(3==type)?{
        ????????criteria.andEmailEqualTo(param);
        ????}
        ????//執(zhí)行查詢
        ????List?list?=?userMapper.selectByExample(example);
        ????//判斷查詢結果是否為空
        ????if(list==null||list.isEmpty()){
        ????????return?ResultObject.ok(true);
        ????}
        ????return?ResultObject.ok(false);
        }

        2)用戶注冊接口

        ? ? ? ? Controller接收一個表單,請求的方法為post。使用TbUser接收表單的內容。調用Service插入數據,返回。

        @RequestMapping(value="/register",method=RequestMethod.POST)
        @ResponseBody
        public?ResultObject?register(TbUser?user){
        ????try?{
        ????????ResultObject?result?=?registerService.register(user);
        ????????System.out.println(result.getStatus()+"===="+result.getMsg());
        ????????return?result;
        ????}?catch?(Exception?e)?{
        ????????e.printStackTrace();
        ????????return?ResultObject.build(500,?"用戶注冊失敗");
        ????}
        }

        ? ??? ? Service接收TbUser參數,對數據進行校驗,校驗成功,插入數據,返回結果。

        public?ResultObject?register(TbUser?user)?{
        ????//校驗數據
        ????//校驗用戶名密碼不能為空
        ????if(StringUtils.isBlank(user.getUsername())||StringUtils.isBlank(user.getPassword())){
        ????????return?ResultObject.build(400,?"用戶名或密碼不能為空");
        ????}
        ????//校驗數據是否重復
        ????//校驗用戶名
        ????ResultObject?result?=?checkData(user.getUsername(),?1);
        ????if(!(boolean)?result.getData()){
        ????????return?ResultObject.build(400,?"用戶名重復");
        ????}
        ????//校驗手機號
        ????if(user.getPhone()!=null){
        ????????result=checkData(user.getPhone(),?2);
        ????????if(!(boolean)?result.getData()){
        ????????????return?ResultObject.build(400,?"手機號重復");
        ????????}
        ????}
        ????//校驗郵箱
        ????if(user.getEmail()!=null){
        ????????result=checkData(user.getEmail(),?3);
        ????????if(!(boolean)?result.getData()){
        ????????????return?ResultObject.build(400,?"郵箱重復");
        ????????}
        ????}
        ????//插入數據
        ????user.setCreated(new?Date());
        ????user.setUpdated(new?Date());
        ????//密碼MD5加密
        ????user.setPassword(DigestUtils.md5DigestAsHex(user.getPassword().getBytes()));
        ????userMapper.insert(user);
        ????return?ResultObject.ok();
        }

        2.用戶登錄

        1)用戶登錄接口

        ? ? ? ? Controller接收兩個參數,一個是用戶名,一個是密碼,請求的方法為post。調用Service方法返回登錄處理結果,響應json數據。

        @RequestMapping(value="/user/login",method=RequestMethod.POST)
        @ResponseBody
        public?ResultObject?login(String?username,String?password,HttpServletRequest?request,HttpServletResponse?response){
        ????try?{
        ????????ResultObject?result?=?loginService.login(username,?password,?request,?response);
        ????????return?result;
        ????}?catch?(Exception?e)?{
        ????????e.printStackTrace();
        ????????return?ResultObject.build(500,?"登錄失敗");
        ????}
        }

        ? ??? ? Service接收用戶名、密碼。校驗密碼是否正確,生成token,向redis中寫入用戶信息,把token寫入cookie,并在返回結果中包含token。

        public?ResultObject?login(String?username,?String?password,
        ????????HttpServletRequest?request,?HttpServletResponse?response)?{
        ????//校驗用戶名密碼是否正確
        ????TbUserExample?example?=?new?TbUserExample();
        ????Criteria?criteria?=?example.createCriteria();
        ????criteria.andUsernameEqualTo(username);
        ????List?list=userMapper.selectByExample(example);
        ????//取用戶信息
        ????if(list==null||list.isEmpty()){
        ????????return?ResultObject.build(400,?"用戶名或密碼錯誤");
        ????}
        ????TbUser?user=list.get(0);
        ????//校驗密碼
        ????if(!user.getPassword().equals(DigestUtils.md5DigestAsHex(password.getBytes()))){
        ????????return?ResultObject.build(400,?"用戶名或密碼錯誤");
        ????}
        ????//登錄成功,生成token
        ????String?token?=?UUID.randomUUID().toString();
        ????//把用戶信息寫入redis
        ????//key:REDIS_SESSION:{TOKEN}
        ????//value:user轉成json
        ????user.setPassword(null);
        ????jedisClient.set(REDIS_SESSION_KEY+":"+token,?JsonUtils.objectToJson(user));
        ????//設置session過期時間
        ????jedisClient.expire(REDIS_SESSION_KEY+":"+token,?SESSION_EXPIRE);
        ????//寫cookie
        ????CookieUtils.setCookie(request,?response,?"PSP_TOKEN",?token);
        ????return?ResultObject.ok(token);
        }

        2)通過token查詢用戶信息

        ? ? ? ? Controller從url中取token的內容,調用Service取用戶信息,響應json數據。

        @RequestMapping("/user/token/{token}")
        @ResponseBody
        public?Object?getUserByToken(@PathVariable?String?token,String?callback){
        ????try?{
        ????????ResultObject?result?=?loginService.getUserByToken(token);
        ????????if(StringUtils.isNotBlank(callback)){
        ????????????System.out.println("callback!!");
        ????????????MappingJacksonValue?mappingJacksonValue=new?MappingJacksonValue(result);
        ????????????System.out.println(mappingJacksonValue.toString());
        ????????????return?mappingJacksonValue;
        ????????}
        ????????return?result;
        ????}?catch?(Exception?e)?{
        ????????e.printStackTrace();
        ????????return?ResultObject.build(500,?"獲取用戶信息失敗");
        ????}
        }

        ? ??? ? Service接收token,根據token查詢redis,查詢到結果返回用戶對象,更新過期時間。如果查詢不到結果,返回Session已經過期,狀態(tài)碼400。

        public?ResultObject?getUserByToken(String?token)?{
        ????//根據token取用戶信息
        ????String?json?=?jedisClient.get(REDIS_SESSION_KEY+":"+token);
        ????//判斷是否查詢到結果
        ????if(StringUtils.isBlank(json)){
        ????????return?ResultObject.build(400,?"用戶session已過期");
        ????}
        ????//把json轉換成java對象
        ????TbUser?user?=?JsonUtils.jsonToPojo(json,?TbUser.class);
        ????//更新session過期時間
        ????jedisClient.expire(REDIS_SESSION_KEY+":"+token,?SESSION_EXPIRE);
        ????return?ResultObject.ok(user);
        }

        2.展示注冊和登錄頁面

        ? ? ? ? 在SSO系統(tǒng)中只有登錄注冊功能,所以只需要兩個頁面就可以了,下面是其跳轉Controller

        @Controller
        public?class?PageController?{
        ????/**
        ?????*?展示登錄頁面
        ?????*/
        ????@RequestMapping("/page/login")
        ????public?String?showLogin(String?redirectURL,Model?model){
        ????????//需要把參數傳遞到jsp,頁面回調
        ????????model.addAttribute("redirect",?redirectURL);
        ????????return?"login";
        ????}
        ?
        ????/**
        ?????*?展示注冊頁面
        ?????*/
        ????@RequestMapping("/page/register")
        ????public?String?showRegister(){
        ????????return?"register";
        ????}
        }

        ? ? ? ? 我們這里為了解決登錄回調,在登錄頁面的js實現(xiàn)如下:

        var?redirectUrl?=?"${redirect}";
        var?LOGIN?=?{
        ????????checkInput:function()?{
        ????????????if?($("#loginname").val()?==?"")?{
        ????????????????alert("用戶名不能為空");
        ????????????????$("#loginname").focus();
        ????????????????return?false;
        ????????????}
        ????????????if?($("#nloginpwd").val()?==?"")?{
        ????????????????alert("密碼不能為空");
        ????????????????$("#nloginpwd").focus();
        ????????????????return?false;
        ????????????}
        ????????????return?true;
        ????????},
        ????????doLogin:function()?{
        ????????????$.post("/user/login",?$("#formlogin").serialize(),function(data){
        ????????????????if?(data.status?==?200)?{
        ????????????????????alert("登錄成功!");
        ????????????????????if?(redirectUrl?==?"")?{
        ????????????????????????location.href?=?"http://www.psp.com";
        ????????????????????}?else?{
        ????????????????????????location.href?=?redirectUrl;
        ????????????????????}
        ????????????????}?else?{
        ????????????????????alert("登錄失敗,原因是:"?+?data.msg);
        ????????????????????$("#loginname").select();
        ????????????????}
        ????????????});
        ????????},
        ????????login:function()?{
        ????????????if?(this.checkInput())?{
        ????????????????this.doLogin();
        ????????????}
        ????????}???
        };
        $(function(){
        ????$("#loginsubmit").click(function(){
        ????????LOGIN.login();
        ????});
        });

        3、其他系統(tǒng)整合SSO

        ? ? ? ? 現(xiàn)在我們就來演示其他系統(tǒng)對SSO進行整合,這里就以門戶系統(tǒng)整合SSO為例。

        1.門戶登錄

        ? ??? ??當用戶在首頁點擊登錄或者注冊的時候需要跳轉到sso系統(tǒng)。進行相應的操作。登錄成功跳轉到首頁。首頁應該顯示當前登錄的用戶。首先門戶系統(tǒng)的登錄按鈕代碼如下,

        "http://sso.psp.com/user/page/login">登錄

        只是一個簡單的超鏈接,跳轉到SSO登錄頁面,并進行相關的登錄操作,當登錄完成后,在首頁展示用戶。其前端實現(xiàn)如下,

        checkLogin?:?function(){
        ????var?_ticket?=?$.cookie("PSP_TOKEN");
        ????if(!_ticket){
        ????????return?;
        ????}
        ????$.ajax({
        ????????url?:?"http://sso.psp.com/user/token/"?+?_ticket,
        ????????dataType?:?"json",
        ????????type?:?"GET",
        ????????success?:?function(data){
        ????????????if(data.status?==?200){
        ????????????????var?username?=?data.data.username;
        ????????????????var?html?=?username?+?",您好!";
        ????????????????$("#loginbar").html(html);
        ????????????}
        ????????}
        ????});
        }

        2.登錄攔截器

        ? ??? ? 在Poratl系統(tǒng)中,對于有些頁面是需要登錄之后才能訪問的,比如訂單頁面,當用戶查看訂單頁面時此時必須要求用戶登錄,可以使用攔截器來實現(xiàn)。攔截器的處理流程為:

        • 攔截請求url

        • 從cookie中取token

        • 如果沒有toke跳轉到登錄頁面。

        • 取到token,需要調用sso系統(tǒng)的服務查詢用戶信息。

        • 如果用戶session已經過期,跳轉到登錄頁面

        • 如果沒有過期,放行。

        ?其中攔截器配置如下,攔截order下的所有操作

        ?
        ????
        ????????"/order/**"/>
        ????????"com.psp.portal.interceptor.LoginInterceptor"/>
        ????

        ?

        然后在springmvc中需要實現(xiàn)HandlerInterceptor接口。

        public?class?LoginInterceptor?implements?HandlerInterceptor?{

        ????@Autowired
        ????private?UserService?userService;
        ????@Value("${SSO_LOGIN_URL}")
        ????private?String?SSO_LOGIN_URL;
        ?
        ????@Override
        ????public?boolean?preHandle(HttpServletRequest?request,?HttpServletResponse?response,
        ????????????Object?object)?throws?Exception?{
        ????????//?1、攔截請求url
        ????????//?2、從cookie中取token
        ????????//?3、如果沒有toke跳轉到登錄頁面。
        ????????//?4、取到token,需要調用sso系統(tǒng)的服務查詢用戶信息。
        ????????TbUser?user?=?userService.getUserByToken(request,?response);
        ????????//?5、如果用戶session已經過期,跳轉到登錄頁面
        ????????if?(user?==?null)?{
        ????????????response.sendRedirect(SSO_LOGIN_URL+"?redirectURL="+request.getRequestURI());
        ????????????return?false;
        ????????}
        ????????//把用戶對象放入request中
        ????????request.setAttribute("user",?user);
        ????????//?6、如果沒有過期,放行。
        ????????return?true;
        ????}
        ????@Override
        ????public?void?afterCompletion(HttpServletRequest?arg0,
        ????????????HttpServletResponse?response,?Object?object,?Exception?exception)
        ????????????throws?Exception?{
        ????}
        ????@Override
        ????public?void?postHandle(HttpServletRequest?request,?HttpServletResponse?response,
        ????????????Object?object,?ModelAndView?modelAndView)?throws?Exception?{
        ????}
        }

        其對應的Service作用為,根據token取用戶信息,如果取到返回TbUser對象,如果取不到,返回null。

        @Service
        public?class?UserServiceImpl?implements?UserService?{

        ????@Value("${SSO_BASE_URL}")
        ????private?String?SSO_BASE_URL;
        ????@Value("${SSO_USER_TOKEN_SERVICE}")
        ????private?String?SSO_USER_TOKEN_SERVICE;
        ?
        ?
        ????@Override
        ????public?TbUser?getUserByToken(HttpServletRequest?request,
        ????????????HttpServletResponse?response)?{
        ????????try?{
        ????????????//從cookie中獲取token
        ????????????String?token?=?CookieUtils.getCookieValue(request,?"PSP_TOKEN");
        ????????????//判斷token是否有值
        ????????????if(StringUtils.isBlank(token)){
        ????????????????return?null;
        ????????????}
        ????????????//調用sso的查詢服務
        ????????????String?json?=?HttpClientUtil.doGet(SSO_BASE_URL+SSO_USER_TOKEN_SERVICE+token);
        ????????????//把json轉換成java對象
        ????????????ResultObject?result?=?ResultObject.format(json);
        ????????????if(result.getStatus()!=200){
        ????????????????return?null;
        ????????????}
        ????????????//取用戶對象
        ????????????result?=?ResultObject.formatToPojo(json,?TbUser.class);
        ????????????TbUser?user=(TbUser)?result.getData();
        ????????????return?user;
        ????????}?catch?(Exception?e)?{
        ????????????return?null;
        ????????}
        ????}
        }






        版權聲明:本文為博主原創(chuàng)文章,遵循?CC 4.0 BY-SA?版權協(xié)議,轉載請附上原文出處鏈接和本聲明。

        本文鏈接:

        https://blog.csdn.net/qq_22172133/article/details/82291112






        粉絲福利:108本java從入門到大神精選電子書領取

        ???

        ?長按上方鋒哥微信二維碼?2 秒
        備注「1234」即可獲取資料



        感謝點贊支持下哈?

        瀏覽 36
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            孕妇张开双腿任我玩 | 欧美精品伦理 | 7799天天综合症 | 曰韩成人无码一区二区三区四区 | 青草网在线观看 | 欧美老人美女做爱视频免费链接 | 国产久艹视频 | 美女搞基网站在线观看 | 午夜成人免费毛片 | 国产精品视频2021 |