宅男在线永久免费观看网直播,亚洲欧洲日产国码无码久久99,野花社区在线观看视频,亚洲人交乣女bbw,一本一本久久a久久精品综合不卡

全部
常見問題
產(chǎn)品動態(tài)
精選推薦

什么是單點登錄

管理 管理 編輯 刪除

一、什么是單點登錄?


單點登錄的英文名叫做:Single Sign On(簡稱SSO)。

在初學/以前的時候,一般我們就單系統(tǒng),所有的功能都在同一個系統(tǒng)上。

后來,我們?yōu)榱撕侠砝觅Y源和降低耦合性,于是把單系統(tǒng)拆分成多個子系統(tǒng)。

回顧:分布式基礎知識

比如阿里系的淘寶和天貓,很明顯地我們可以知道這是兩個系統(tǒng),但是你在使用的時候,登錄了天貓,淘寶也會自動登錄。

簡單來說,單點登錄就是在多個系統(tǒng)中,用戶只需一次登錄,各個系統(tǒng)即可感知該用戶已經(jīng)登錄。

二、回顧單系統(tǒng)登錄


在我初學JavaWeb的時候,登錄和注冊是我做得最多的一個功能了(初學Servlet的時候做過、學SpringMVC的時候做過、跟著做項目的時候做過…),反正我也數(shù)不清我做了多少次登錄和注冊的功能了…這里簡單講述一下我們初學時是怎么做登錄功能的。

眾所周知,HTTP是無狀態(tài)的協(xié)議,這意味著服務器無法確認用戶的信息。于是乎,W3C就提出了:給每一個用戶都發(fā)一個通行證,無論誰訪問的時候都需要攜帶通行證,這樣服務器就可以從通行證上確認用戶的信息。通行證就是Cookie。

如果說Cookie是檢查用戶身上的”通行證“來確認用戶的身份,那么Session就是通過檢查服務器上的”客戶明細表“來確認用戶的身份的。Session相當于在服務器中建立了一份“客戶明細表”。

HTTP協(xié)議是無狀態(tài)的,Session不能依據(jù)HTTP連接來判斷是否為同一個用戶。于是乎:服務器向用戶瀏覽器發(fā)送了一個名為JESSIONID的Cookie,它的值是Session的id值。其實Session是依據(jù)Cookie來識別是否是同一個用戶。

所以,一般我們單系統(tǒng)實現(xiàn)登錄會這樣做:

登錄:將用戶信息保存在Session對象中

如果在Session對象中能查到,說明已經(jīng)登錄

如果在Session對象中查不到,說明沒登錄(或者已經(jīng)退出了登錄)

注銷(退出登錄):從Session中刪除用戶的信息

記住我(關(guān)閉掉瀏覽器后,重新打開瀏覽器還能保持登錄狀態(tài)):配合Cookie來用

我之前Demo的代碼,可以參考一下:

/**

用戶登陸
*/
@PostMapping(value = “/user/session”, produces = {“application/json;charset=UTF-8”})
public Result login(String mobileNo, String password, String inputCaptcha, HttpSession session, HttpServletResponse response) {

//判斷驗證碼是否正確
if (WebUtils.validateCaptcha(inputCaptcha, “captcha”, session)) {

 //判斷有沒有該用戶
 User user = userService.userLogin(mobileNo, password);
 if (user != null) {
     /*設置自動登陸,一個星期.  將token保存在數(shù)據(jù)庫中*/
     String loginToken = WebUtils.md5(new Date().toString() + session.getId());
     user.setLoginToken(loginToken);
     User user1 = userService.userUpload(user);

     session.setAttribute("user", user1);

     CookieUtil.addCookie(response,"loginToken",loginToken,604800);

     return ResultUtil.success(user1);

 } else {
     return ResultUtil.error(ResultEnum.LOGIN_ERROR);
 }
} else {
return ResultUtil.error(ResultEnum.CAPTCHA_ERROR);
}

}

/**

用戶退出
*/
@DeleteMapping(value = “/session”, produces = {“application/json;charset=UTF-8”})
public Result logout(HttpSession session,HttpServletRequest request,HttpServletResponse response ) {

//刪除session和cookie
session.removeAttribute(“user”);

CookieUtil.clearCookie(request, response, “l(fā)oginToken”);

return ResultUtil.success();
}
/**

@author ozc

@version 1.0

攔截器;實現(xiàn)自動登陸功能
*/
public class UserInterceptor implements HandlerInterceptor {

@Autowired
private UserService userService;

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {
User sessionUser = (User) request.getSession().getAttribute(“user”);

// 已經(jīng)登陸了,放行
if (sessionUser != null) {
    return true;
} else {
    //得到帶過來cookie是否存在
    String loginToken = CookieUtil.findCookieByName(request, "loginToken");
    if (StringUtils.isNotBlank(loginToken)) {
        //到數(shù)據(jù)庫查詢有沒有該Cookie
        User user = userService.findUserByLoginToken(loginToken);
        if (user != null) {
            request.getSession().setAttribute("user", user);
            return true;
        } else {
            //沒有該Cookie與之對應的用戶(Cookie不匹配)
            CookieUtil.clearCookie(request, response, "loginToken");
            return false;
        }
    } else {

        //沒有cookie、也沒有登陸。是index請求獲取用戶信息,可以放行
        if (request.getRequestURI().contains("session")) {
            return true;
        }

        //沒有cookie憑證
        response.sendRedirect("/login.html");
        return false;
    }
}
}
}

總結(jié)一下上面代碼的思路:

用戶登錄時,驗證用戶的賬戶和密碼

生成一個Token保存在數(shù)據(jù)庫中,將Token寫到Cookie中

將用戶數(shù)據(jù)保存在Session中

請求時都會帶上Cookie,檢查有沒有登錄,如果已經(jīng)登錄則放行

如果沒看懂的同學,建議回顧Session和Cookie和HTTP:

介紹會話技術(shù)、Cookie的API、詳解、應用

Session介紹、API、生命周期、應用、與Cookie區(qū)別

什么是HTTP


三、多系統(tǒng)登錄的問題與解決


3.1 Session不共享問題

單系統(tǒng)登錄功能主要是用Session保存用戶信息來實現(xiàn)的,但我們清楚的是:多系統(tǒng)即可能有多個Tomcat,而Session是依賴當前系統(tǒng)的Tomcat,所以系統(tǒng)A的Session和系統(tǒng)B的Session是不共享的。

b2744202305171204571477.png

解決系統(tǒng)之間Session不共享問題有一下幾種方案:

Tomcat集群Session全局復制(集群內(nèi)每個tomcat的session完全同步)【會影響集群的性能呢,不建議】

根據(jù)請求的IP進行Hash映射到對應的機器上(這就相當于請求的IP一直會訪問同一個服務器)【如果服務器宕機了,會丟失了一大部分Session的數(shù)據(jù),不建議】

把Session數(shù)據(jù)放在Redis中(使用Redis模擬Session)【建議】

如果還不了解Redis的同學,建議移步(Redis合集)

我們可以將登錄功能單獨抽取出來,做成一個子系統(tǒng)。

SSO(登錄系統(tǒng))的邏輯如下:

// 登錄功能(SSO單獨的服務)
@Override
public TaotaoResult login(String username, String password) throws Exception {

//根據(jù)用戶名查詢用戶信息
TbUserExample example = new TbUserExample();
Criteria criteria = example.createCriteria();
criteria.andUsernameEqualTo(username);
List list = userMapper.selectByExample(example);
if (null == list || list.isEmpty()) {
    return TaotaoResult.build(400, "用戶不存在");
}
//核對密碼
TbUser user = list.get(0);
if (!DigestUtils.md5DigestAsHex(password.getBytes()).equals(user.getPassword())) {
    return TaotaoResult.build(400, "密碼錯誤");
}
//登錄成功,把用戶信息寫入redis
//生成一個用戶token
String token = UUID.randomUUID().toString();
jedisCluster.set(USER_TOKEN_KEY + ":" + token, JsonUtils.objectToJson(user));
//設置session過期時間
jedisCluster.expire(USER_TOKEN_KEY + ":" + token, SESSION_EXPIRE_TIME);
return TaotaoResult.ok(token);
}

其他子系統(tǒng)登錄時,請求SSO(登錄系統(tǒng))進行登錄,將返回的token寫到Cookie中,下次訪問時則把Cookie帶上:

public TaotaoResult login(String username, String password,
HttpServletRequest request, HttpServletResponse response) {
//請求參數(shù)
Map param = new HashMap<>();
param.put(“username”, username);
param.put(“password”, password);
//登錄處理
String stringResult = HttpClientUtil.doPost(REGISTER_USER_URL + USER_LOGIN_URL, param);
TaotaoResult result = TaotaoResult.format(stringResult);
//登錄出錯
if (result.getStatus() != 200) {
return result;
}
//登錄成功后把取token信息,并寫入cookie
String token = (String) result.getData();
//寫入cookie
CookieUtils.setCookie(request, response, “TT_TOKEN”, token);
//返回成功
return result;

}

總結(jié):

SSO系統(tǒng)生成一個token,并將用戶信息存到Redis中,并設置過期時間

其他系統(tǒng)請求SSO系統(tǒng)進行登錄,得到SSO返回的token,寫到Cookie中

每次請求時,Cookie都會帶上,攔截器得到token,判斷是否已經(jīng)登錄

到這里,其實我們會發(fā)現(xiàn)其實就兩個變化:

將登陸功能抽取為一個系統(tǒng)(SSO),其他系統(tǒng)請求SSO進行登錄

本來將用戶信息存到Session,現(xiàn)在將用戶信息存到Redis

3.2 Cookie跨域的問題

上面我們解決了Session不能共享的問題,但其實還有另一個問題。Cookie是不能跨域的

比如說,我們請求https://www.google.com/時,瀏覽器會自動把google.com的Cookie帶過去給google的服務器,而不會把https://www.baidu.com/的Cookie帶過去給google的服務器。

這就意味著,由于域名不同,用戶向系統(tǒng)A登錄后,系統(tǒng)A返回給瀏覽器的Cookie,用戶再請求系統(tǒng)B的時候不會將系統(tǒng)A的Cookie帶過去。

針對Cookie存在跨域問題,有幾種解決方案:

服務端將Cookie寫到客戶端后,客戶端對Cookie進行解析,將Token解析出來,此后請求都把這個Token帶上就行了

多個域名共享Cookie,在寫到客戶端的時候設置Cookie的domain。

將Token保存在SessionStroage中(不依賴Cookie就沒有跨域的問題了)

到這里,我們已經(jīng)可以實現(xiàn)單點登錄了。

3.3 CAS原理

說到單點登錄,就肯定會見到這個名詞:CAS (Central Authentication Service),下面說說CAS是怎么搞的。

如果已經(jīng)將登錄單獨抽取成系統(tǒng)出來,我們還能這樣玩。現(xiàn)在我們有兩個系統(tǒng),分別是www.java3y.com和www.java4y.com,一個SSOwww.sso.com

3add2202305171404027906.png

首先,用戶想要訪問系統(tǒng)Awww.java3y.com受限的資源(比如說購物車功能,購物車功能需要登錄后才能訪問),系統(tǒng)Awww.java3y.com發(fā)現(xiàn)用戶并沒有登錄,于是重定向到sso認證中心,并將自己的地址作為參數(shù)。請求的地址如下:

www.sso.com?service=www.java3y.com

sso認證中心發(fā)現(xiàn)用戶未登錄,將用戶引導至登錄頁面,用戶進行輸入用戶名和密碼進行登錄,用戶與認證中心建立全局會話(生成一份Token,寫到Cookie中,保存在瀏覽器上)

603bb202305171410286826.png

隨后,認證中心重定向回系統(tǒng)A,并把Token攜帶過去給系統(tǒng)A,重定向的地址如下:

www.java3y.com?token=xxxxxxx

接著,系統(tǒng)A去sso認證中心驗證這個Token是否正確,如果正確,則系統(tǒng)A和用戶建立局部會話(創(chuàng)建Session)。到此,系統(tǒng)A和用戶已經(jīng)是登錄狀態(tài)了。

8ec44202305171411314653.png

此時,用戶想要訪問系統(tǒng)Bwww.java4y.com受限的資源(比如說訂單功能,訂單功能需要登錄后才能訪問),系統(tǒng)Bwww.java4y.com發(fā)現(xiàn)用戶并沒有登錄,于是重定向到sso認證中心,并將自己的地址作為參數(shù)。請求的地址如下:

www.sso.com?service=www.java4y.com

注意,因為之前用戶與認證中心www.sso.com已經(jīng)建立了全局會話(當時已經(jīng)把Cookie保存到瀏覽器上了),所以這次系統(tǒng)B重定向到認證中心www.sso.com是可以帶上Cookie的。

認證中心根據(jù)帶過來的Cookie發(fā)現(xiàn)已經(jīng)與用戶建立了全局會話了,認證中心重定向回系統(tǒng)B,并把Token攜帶過去給系統(tǒng)B,重定向的地址如下:

www.java4y.com?token=xxxxxxx

接著,系統(tǒng)B去sso認證中心驗證這個Token是否正確,如果正確,則系統(tǒng)B和用戶建立局部會話(創(chuàng)建Session)。到此,系統(tǒng)B和用戶已經(jīng)是登錄狀態(tài)了。

73035202305171412356030.png

看到這里,其實SSO認證中心就類似一個中轉(zhuǎn)站。

請登錄后查看

CRMEB-慕白寒窗雪 最后編輯于2023-05-17 14:15:41

快捷回復
回復
回復
回復({{post_count}}) {{!is_user ? '我的回復' :'全部回復'}}
排序 默認正序 回復倒序 點贊倒序

{{item.user_info.nickname ? item.user_info.nickname : item.user_name}} LV.{{ item.user_info.bbs_level || item.bbs_level }}

作者 管理員 企業(yè)

{{item.floor}}# 同步到gitee 已同步到gitee {{item.is_suggest == 1? '取消推薦': '推薦'}}
{{item.is_suggest == 1? '取消推薦': '推薦'}}
沙發(fā) 板凳 地板 {{item.floor}}#
{{item.user_info.title || '暫無簡介'}}
附件

{{itemf.name}}

{{item.created_at}}  {{item.ip_address}}
打賞
已打賞¥{{item.reward_price}}
{{item.like_count}}
{{item.showReply ? '取消回復' : '回復'}}
刪除
回復
回復

{{itemc.user_info.nickname}}

{{itemc.user_name}}

回復 {{itemc.comment_user_info.nickname}}

附件

{{itemf.name}}

{{itemc.created_at}}
打賞
已打賞¥{{itemc.reward_price}}
{{itemc.like_count}}
{{itemc.showReply ? '取消回復' : '回復'}}
刪除
回復
回復
查看更多
打賞
已打賞¥{{reward_price}}
874
{{like_count}}
{{collect_count}}
添加回復 ({{post_count}})

相關(guān)推薦

快速安全登錄

使用微信掃碼登錄
{{item.label}} 加精
{{item.label}} {{item.label}} 板塊推薦 常見問題 產(chǎn)品動態(tài) 精選推薦 首頁頭條 首頁動態(tài) 首頁推薦
取 消 確 定
回復
回復
問題:
問題自動獲取的帖子內(nèi)容,不準確時需要手動修改. [獲取答案]
答案:
提交
bug 需求 取 消 確 定
打賞金額
當前余額:¥{{rewardUserInfo.reward_price}}
{{item.price}}元
請輸入 0.1-{{reward_max_price}} 范圍內(nèi)的數(shù)值
打賞成功
¥{{price}}
完成 確認打賞

微信登錄/注冊

切換手機號登錄

{{ bind_phone ? '綁定手機' : '手機登錄'}}

{{codeText}}
切換微信登錄/注冊
暫不綁定
CRMEB客服

CRMEB咨詢熱線 咨詢熱線

400-8888-794

微信掃碼咨詢

CRMEB開源商城下載 源碼下載 CRMEB幫助文檔 幫助文檔
返回頂部 返回頂部
CRMEB客服