sso系統使用


一:什么是sso(single sign on) ? 

  sso(單點登錄系統)簡單說就是客戶端第一次訪問應用1的時候,由於沒有登錄,會被引導到登錄頁面進行登錄,如果登錄校驗通過,將返回一個認證信息ticket,作為認證憑據。下次客戶端訪問應用2的時候,發送的url請求會攜帶着ticket作為自己的認證憑據,服務器會將該請求攜帶的ticket交給認證中心進行比對,檢驗,如果檢驗通過,應用2在可以不登錄的情況下訪問內部的資源信息。

 

二:單點登錄系統的整個登錄過程

 

(1)傳統登錄方式(單應用下)

 

圖一:為傳統的登錄方式。在一個工程下這套登錄機制是沒有問題的。但是集群環境下會出現要求用戶多次登錄的情況

 

如何解決集群環境中用戶多次登錄的情況?

解決多次登錄的方案有兩種:就是解決session共享的問題

1.配置tomcat集群,在tomcat中配置session共享(session復制),但是問題是tomcat部署的節點過多,會出現性能問題。所以一般不適用這種方式

2.可以使用session服務器,是每個節點保持無狀態,保存session信息。模擬session。

單點登錄就是為了解決session共享問題提出的一套解決方案。使用redis模擬session,實現session的統一管理。

(2)使用單點登錄的業務流程

 

 

      

 

 

 

 登錄流程解析:

第一步:第一次訪問,進入登錄系統輸入用戶名密碼進行驗證登錄,如果登錄成功,生成Token對象,作為認證令牌(token相當於原來的jsessionid字符串,這里使用uuid)  

第二步:將返回的token對象信息存入redis服務器。key 就是token , value就是登錄用戶的信息

第三步:既然是模擬session,所以也需要設置key的過期時間。

第四步:將token(存儲的key)寫入cookie中,作為用戶請求的url參數信息

第五步:用戶第二次訪問,首先檢查用戶是否登錄,將寫入cookie中的token作為請求參數,服務器會從url中解析token的值,然后將解析的token值作為key查詢redis服務器;如果查詢結果為空,表示session已經過期,要求客戶端跳轉到登錄頁面完成登錄操作;如果查詢結果不為空,需要將查詢的信息(登錄用戶的信息)作為對象返回,然后重新設置key的過期時間。

第六步:解決跨域的問題,使用js發送ajax請求, 使用jsonp解決跨域問題。需要服務器返回的數據格式為mycallback:{id:xx,name:xx},所以將返回的json數據進行拼接成要求的格式即可。

三:登錄過程的核心代碼

    @Override
    public E3Result login(String username, String password) {
        try {
            TbUserExample example = new TbUserExample();
            Criteria criteria = example.createCriteria();
            criteria.andUsernameEqualTo(username);
            List<TbUser> list = userMapper.selectByExample(example);
            if (list == null || list.size() == 0) {
                // 登錄失敗
                return E3Result.build(400, "用戶名或密碼錯誤");
            }
            //獲得用戶對象
            TbUser user = list.get(0);
            //校驗用戶密碼
            if(!(user.getPassword()).equals(DigestUtils.md5Hex(password.getBytes()))) {
                //校驗失敗
                return E3Result.build(400, "用戶名或者密碼錯誤");
            }

            //登錄成功
            //1.創建token對象,使用uuid
            String token = UUID.randomUUID().toString();
            //2.將uuid作為key,用戶信息作為value值存入redis中
            jedisClient.set("USER_INFO:"+token, JsonUtils.objectToJson(user));
            //3.設置過期時間,半小時
            jedisClient.expire("USER_INFO:"+token, 1800);
            
            //4.返回登錄成功的信息
            
            return E3Result.ok(token);
            
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }
View Code

解決跨域問題的服務端

    @RequestMapping(value = "/user/token/{token}", produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    public String getTokenName(@PathVariable String token, String callback) {
        E3Result result = tokenService.getToken(token);
        if (StringUtils.isNotBlank(callback)) {
            // 拼接成頁面需要的數據給事
            // mycall({id:1,name:z});
            String json = callback + "(" + JsonUtils.objectToJson(result) + ");";
            System.out.println(json);
            return json;
        }
        return JsonUtils.objectToJson(result);
    }

客戶端代碼:

var E3MALL = {
    checkLogin : function(){
    //COOKIE_TOKEN_KEY設置的cookie的name值 var _ticket = $.cookie("COOKIE_TOKEN_KEY"); if(!_ticket){ return ; } $.ajax({ url : "http://localhost:8088/user/token/" + _ticket, dataType : "jsonp", type : "GET", success : function(data){ if(data.status == 200){ var username = data.data.username; var html = username + ",歡迎!
<a href=\"http://www.e3mall.cn/user/logout.html\" class=\"link-logout\">[退出]</a>"; $("#loginbar").html(html); } } }); } } $(function(){ // 查看是否已經登錄,如果已經登錄查詢登錄信息 E3MALL.checkLogin(); });

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM