JAVA SSM框架下+Redis 實(shí)現(xiàn)單點(diǎn)登錄(手把手教,一步步都很詳細(xì))瀑罗,含源碼

Redis的安裝和引用參考上一篇:Redis下載鏈接

1:什么是單點(diǎn)登錄胸嘴?
答:單點(diǎn)登錄的英文名叫做:Single Sign On(簡稱SSO)。
一般我們的模塊都是在同一個(gè)系統(tǒng)下斩祭,同一個(gè)tomcat(如圖筛谚,以商城為例)


image

后來為了維護(hù)和資源我們把一個(gè)系統(tǒng)拆成多個(gè)子系統(tǒng)。


image

而單點(diǎn)登錄就是其中的一部分停忿。
我們有多個(gè)系統(tǒng)驾讲,每個(gè)系統(tǒng)都要輸入一次賬號(hào)和密碼的話就會(huì)變得很麻煩,這時(shí)候就需要單點(diǎn)登錄席赂,只要其中一個(gè)子系統(tǒng)登錄的話吮铭,其他系統(tǒng)都能自動(dòng)登錄。最為熟悉的例子就是淘寶和天貓颅停,如果你淘寶登錄后谓晌,打開天貓就能自動(dòng)登錄無需再輸入賬號(hào)和密碼。

2:實(shí)現(xiàn)單點(diǎn)登錄的思路(整個(gè)頁面的流程)

image

假設(shè)兩個(gè)頁面
用戶A系統(tǒng)沒登陸癞揉,B系統(tǒng)沒登陸
這時(shí)用戶在A登陸纸肉,A生成token令牌存入cookie溺欧,redis存入已經(jīng)登錄參數(shù)
然后用戶打開B系統(tǒng)登錄頁面,B系統(tǒng)登錄頁面發(fā)送請(qǐng)求柏肪,后端通過cookie獲取到用戶在A系統(tǒng)登錄的信息
判斷獲取到的信息沒有錯(cuò)誤進(jìn)行自動(dòng)登陸

3:Demo代碼(兩個(gè)頁面的代碼是一樣的姐刁,路徑什么的改改就行了)
簡單的登陸jq,ajax請(qǐng)求
前端

<body background="jquery/loginbg.jpg">
<div>
<form  style="margin: auto; width:230px" class="form-signin"  >
<h2 class="form-signin-heading"><font color="white">SSO1用戶登錄</font></h2>
<!-- <label>賬號(hào):</label> -->
<input type="text" id="txtUsername" class="form-control" name="username" placeholder="請(qǐng)輸入賬號(hào)" /><br/>
<!-- <label>密碼:</label> -->
<input type="password" id="txtPassword" class="form-control" name="password" placeholder="請(qǐng)輸入密碼" /><br/>
<!-- <input type="submit" value="提交" /> -->
 <a class="btn btn-primary btn-block" id="tijiao">提交</a><br>
<!-- <button class="btn btn-primary btn-block"  id="tijiao">提交</button><br> -->
  <button class="btn btn-primary btn-block"  >重置</button><br>
<!-- <input type="reset" value="重置" /> -->
<input type="button" class="btn btn-primary btn-block" value="注冊(cè)" onclick="window.location.href='add.jsp';"/>
</div>
<div id="chartmain" style="width:600px; height: 400px;  margin: auto; " class="form-signin"></div>
 
</body>
<script type="text/javascript">
    $("#tijiao").click(function(){
        var paramMap = {};
        paramMap.username = $("#txtUsername").val();
        paramMap.userpasswd = $("#txtPassword").val();
        $.ajax({
            type:'POST',
            data:JSON.stringify(paramMap),
            dataType:'JSON',
            url:"user/slogin",
            contentType :"application/json;charset=UTF-8",
            async: true,
            error:function(jqXHR){
                 alert("發(fā)生錯(cuò)誤:"+ jqXHR.status); 
                },
             success:function(data){
                 if(data){
                    if(data.state == "success"){
                        window.location.href ='index.jsp';
                    }else if(data.state == "fault"){
                        window.location.href ='login.jsp';
                    } 
                 }
                  
                 }
        });
    })
    window.onload = function(){
        var paramMap = {};
        var i = 0;
        paramMap.username = $("#txtUsername").val();
        paramMap.userpasswd = $("#txtPassword").val();
        $.ajax({
            type:'POST',
            data:JSON.stringify(paramMap),
            dataType:'JSON',
            url:"user/slogin",
//          xhrFields: {
//              withCredentials: true // 攜帶跨域cookie
//          },
            contentType :"application/json;charset=UTF-8",
            async: true,
            error:function(jqXHR){
                 alert("發(fā)生錯(cuò)誤:"+ jqXHR.status); 
                },
             success:function(data){
                 if(data){
                    if(data.state == "success"){
                        window.location.href ='index.jsp';
                    }else if(data.state == "fault"){
                        debugger;
                        var str=location.href; //取得整個(gè)地址欄
                        var num=str.indexOf("=") 
                        str=str.substr(num+1);
                        if(str!="1"||str==null){
                            window.location.href ='login.jsp?state=1';
                        }
                        
                    } 
                 }
                  
                 }
        });
}
    
    
    
    
</script>

后端

    /**
     * 登陸
     * @param <Account>
     * @param model
     * @param session
     * @return
     * @throws Exception 
     */
    @ResponseBody
    @RequestMapping(value = "/slogin", method = RequestMethod.POST)
    public ResultInfo slogin(@RequestBody Map<String, String> param,
            HttpSession session, HttpServletRequest request,
            ServletResponse response, HttpServletResponse responses)
            throws Exception {
        ResultInfo resultinfo = new ResultInfo();
        
        /**
         * 判斷redis是否連接成功
         */
        //連接本地的 Redis 服務(wù)
        @SuppressWarnings("resource")
        Jedis jedis = new Jedis("localhost");
        System.out.println("連接成功");
        //用戶驗(yàn)證
        String username = param.get("username");
        String passwd = param.get("userpasswd");
        
        if(jedis.exists("islogin")){
            //判斷是否已經(jīng)登錄
            if(!jedis.get("islogin").equals("1")){
                // TODO: handle exception
                resultinfo.setState(StateType.fault);
                jedis.set("islogin", "0");
            }
        }else if(!jedis.exists("islogin") && username.length()==0 && passwd.length()==0){
            resultinfo.setState(StateType.fault);
            return resultinfo;
        }
        
        /**
         * 從cookie中獲取數(shù)據(jù)
         */
        Cookie[] cookies = request.getCookies();
        System.out.println(cookies);
        String cookievalue = null;
        for(Cookie cookiexs : cookies){
            if(cookiexs.getName().equals("token")){
                cookievalue = cookiexs.getValue();
                break;
            }
        }
        
        if(cookievalue!=null){
            //base64解密
            String decusername = null;
            String decpasswd = null;
            int a = 1;
            byte[] decoded = Base64Utils.decode(cookievalue.getBytes());
            String decodeStr = new String(decoded,"UTF-8");
            System.out.println("Base 64 解密后:" + decodeStr);
            //獲取用戶名和密碼
            for(int i=-1; i<=decodeStr.lastIndexOf("=");++i){
            i=decodeStr.indexOf("=",i);
            System.out.print(i+"\t");
            if(a==1){
                decusername = decodeStr.substring(i, i);
                a++;
            }else if(a>1){
                decusername = decodeStr.substring(5,i-6);
                decpasswd = decodeStr.substring(i+1, decodeStr.length()-6);
                a=1;
            }
             System.out.println("賬號(hào)為:"+decusername+"\t"+"密碼為:"+decpasswd);
             
            }
            username = decusername;
            passwd = decpasswd;
        }
        
        
        try {
            if(username  != "" && passwd !=""){
                User user = userService.loginUsername(username);
                if(user ==null){
                    resultinfo.setState(StateType.fault);
                    jedis.set("islogin", "0");
                    return resultinfo;
                }else if(!user.getPassword().equals(passwd)){
                    resultinfo.setState(StateType.fault);
                    jedis.set("islogin", "0");
                    return resultinfo;
                }
                //設(shè)置token
                String token = tokenset(user);
                
                //將數(shù)據(jù)保存到cookie中
                Cookie cookie = new Cookie("token", token);
                //cookie.setMaxAge(600);
                responses.addCookie(cookie);
                
                //將token發(fā)送給客戶端,附帶本次全局會(huì)話的sessionId
                //String allSessionId=request.getSession().getId();
                
                //獲取sessionid
                String sessionid = session.getId();
                
                //設(shè)置狀態(tài)(通過session判斷該瀏覽器與認(rèn)證中心的全局會(huì)話是否已經(jīng)建立)烦味,生成令牌
                //判斷用戶是否登錄
                request.getSession().setAttribute("isLogin", username);
                Map<String, String> tosession = new HashMap<String, String>();
                tosession.put("sessionid", sessionid);
                jedis.set("islogin", "1");
                jedis.set(token,username+passwd);
                jedis.expire("islogin", 120);
//              jedis.expire("token", 600);
                resultinfo.setData(token);
                resultinfo.setState(StateType.success);
            }
             if(jedis.get("islogin").equals("1")){
                 resultinfo.setState(StateType.success);
             }else{
                 resultinfo.setState(StateType.fault);
             }
            
            
        } catch (Exception e) {
            // TODO: handle exception
            resultinfo.setState(StateType.fault);
            resultinfo.setData(e.toString());
        }
        return resultinfo;
            
        
        
    }
/**
     * 設(shè)置token
     */
    private String tokenset(User user) {
        // TODO Auto-generated method stub
        String token = null;
        String sign = "hitomi";
        String param = "name="+user.getUsername()+"passwd="+user.getPassword()+sign;
        token = Base64Utils.encodeToString(param.getBytes());
        return token;
        
    }

此代碼只是簡單的實(shí)現(xiàn)單點(diǎn)登錄的思路和功能聂使,僅供參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請(qǐng)通過簡信或評(píng)論聯(lián)系作者谬俄。
  • 序言:七十年代末柏靶,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子溃论,更是在濱河造成了極大的恐慌屎蜓,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,907評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钥勋,死亡現(xiàn)場(chǎng)離奇詭異炬转,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)笔诵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來姑子,“玉大人乎婿,你說我怎么就攤上這事〗钟樱” “怎么了谢翎?”我有些...
    開封第一講書人閱讀 164,298評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長沐旨。 經(jīng)常有香客問我森逮,道長,這世上最難降的妖魔是什么磁携? 我笑而不...
    開封第一講書人閱讀 58,586評(píng)論 1 293
  • 正文 為了忘掉前任褒侧,我火速辦了婚禮,結(jié)果婚禮上谊迄,老公的妹妹穿的比我還像新娘闷供。我一直安慰自己,他們只是感情好统诺,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評(píng)論 6 392
  • 文/花漫 我一把揭開白布歪脏。 她就那樣靜靜地躺著,像睡著了一般粮呢。 火紅的嫁衣襯著肌膚如雪婿失。 梳的紋絲不亂的頭發(fā)上钞艇,一...
    開封第一講書人閱讀 51,488評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音豪硅,去河邊找鬼哩照。 笑死,一個(gè)胖子當(dāng)著我的面吹牛舟误,可吹牛的內(nèi)容都是我干的葡秒。 我是一名探鬼主播,決...
    沈念sama閱讀 40,275評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼嵌溢,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼眯牧!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起赖草,我...
    開封第一講書人閱讀 39,176評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤学少,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后秧骑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體版确,經(jīng)...
    沈念sama閱讀 45,619評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評(píng)論 3 336
  • 正文 我和宋清朗相戀三年乎折,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了绒疗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,932評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡骂澄,死狀恐怖吓蘑,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情坟冲,我是刑警寧澤磨镶,帶...
    沈念sama閱讀 35,655評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站健提,受9級(jí)特大地震影響琳猫,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜私痹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評(píng)論 3 329
  • 文/蒙蒙 一脐嫂、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧紊遵,春花似錦雹锣、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至桦山,卻和暖如春攒射,著一層夾襖步出監(jiān)牢的瞬間醋旦,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評(píng)論 1 269
  • 我被黑心中介騙來泰國打工会放, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留饲齐,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,095評(píng)論 3 370
  • 正文 我出身青樓咧最,卻偏偏與公主長得像捂人,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子矢沿,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容