溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

J2EE下怎樣模仿token機(jī)制

發(fā)布時(shí)間:2021-11-26 11:06:07 來源:億速云 閱讀:118 作者:柒染 欄目:開發(fā)技術(shù)

這篇文章將為大家詳細(xì)講解有關(guān)J2EE下怎樣模仿token機(jī)制,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。

現(xiàn)在很多移動(dòng)應(yīng)用需要與后臺(tái)交互,與后臺(tái)交互就需要身份認(rèn)證。最初想到用token的方式是當(dāng)初看到微信公眾平臺(tái)的身份認(rèn)證時(shí)采用了token這樣的一個(gè)參數(shù),然后自己也照著實(shí)現(xiàn)了一個(gè)。
說到這個(gè)token機(jī)制,一個(gè)是調(diào)用端,一個(gè)是后臺(tái)。調(diào)用端我用JAVA語(yǔ)言開發(fā)的Android應(yīng)用來展示,后臺(tái)用J2EE來展示。

一、token的獲取
token的獲取其實(shí)就是移動(dòng)端的登錄過程,在登錄的時(shí)候要先向后臺(tái)獲取一個(gè)token值,首先來看登錄時(shí)Android端的代碼:

String name = (EditText)mName.getText().toString();
String password = (EditText)mPsw.getText().toString();

String url2 = "http://"+ip+":"+port+"/test/be/login.do?method=login";

OkHttpClientManager ohm = OkHttpClientManager.getInstance();
OkHttpClientManager.Param[] params = new OkHttpClientManager.Param[]{
                new OkHttpClientManager.Param("name", name),
                new OkHttpClientManager.Param("password", password)};

OkHttpClientManager.ResultCallback cb = new OkHttpClientManager.ResultCallback<String>() {
        @Override
        public void onError(Request request, Exception e) {
                        String resultMsg = "請(qǐng)求失敗,請(qǐng)檢查網(wǎng)絡(luò)連接!";
                        ToastUtil.showToastMsgError(LoginActivity.this, resultMsg);
                        cancleAnimation();//關(guān)閉登錄等待框
        }

        @Override
        public void onResponse(String response) {
                        JSONObject returnJson = JSONObject.parseObject(response);
                        String resultId = returnJson.get("resultId").toString();
                        if (resultId.equals("00")) {
                                token = returnJson.get("token").toString();
                                System.out.println("======================token:" + token);
                                startApp();//進(jìn)入應(yīng)用
                        } else {
                                token = "";
                                String resultMsg = returnJson.get("resultMsg").toString();
                                ToastUtil.showToastMsgError(NewLoginActivity.this, resultMsg);
                                cancleAnimation();
                        }
        }
};

OkHttpClientManager.getInstance().postAsyn(url2,cb, params);

OkHttpClientManager是經(jīng)過封裝的OkHttp的調(diào)用類,可以直接調(diào)用向后臺(tái)發(fā)起http請(qǐng)求。

然后我們來看下后臺(tái)的處理,這里后臺(tái)有幾個(gè)注意點(diǎn):首先,login接口必須不被攔截器和過濾器給攔住,然后將用戶名和密碼傳輸?shù)絚trl層,然后驗(yàn)證該用戶名密碼的真實(shí)有效性,如果合適身份,返回token,如果身份有問題,返回相應(yīng)的提示信息。

@RequestMapping(params="method=login")
@ResponseBody
public String login(HttpServletRequest request,HttpServletResponse response,SysUser command) throws Exception{
    String resStr = "";

    try{
        String name = command.getName();
        String password = command.getPassword();

        UserSession userSession=new UserSession();
        // 設(shè)置usersession登錄模式
        userSession.setDlms("1");
        command.setDlms("1");
        SysUser sysuser=new SysUser();
        Department department=new Department();
        if(name==null||name.length()<1||name.indexOf("'")!=-1){
            throw new Exception("該用戶不存在!");
        }
        if(password==null||password.length()<1||password.indexOf("'")!=-1){
            throw new Exception("該密碼不存在!");
        }

        String strRemoteAddr=FuncUtil.getRemoteIpdz(request); // 獲取ip地址
        System.out.println("strRemoteAddr:"+strRemoteAddr);

        sysuserManager.validateSysuser(command,userSession,strRemoteAddr);//校驗(yàn)用戶名、密碼,有問題會(huì)直接throw異常
        sysuser=this.sysuserManager.getSysuserByUsername(name);//獲取用戶信息
        if(sysuser==null){
            throw new Exception(Constants.SYS_NO_RIGHT);
        }
        sysuser.setIp(strRemoteAddr);// 設(shè)置登錄人員的ip地址
        sysuser.setDlms(command.getDlms());
        department=this.departmentManager.getDepartment(sysuser.getGlbm());
        if(department==null)
            throw new Exception(Constants.SYS_NO_HIGHXZQH);

        UUID token = UUID.randomUUID();
        userSession.setSysuser(sysuser);//sysuser
        userSession.setDepartment(department);
        userSession.setYhdh(sysuser.getYhdh());
        userSession.setGlbm(department.getGlbm());
        userSession.setScdlsj(new Date().getTime()+"");

        RestfulSession.setSession(token.toString(), userSession);

                Map<String, Object> resultMap = new HashMap<String, Object>();
                resultMap.put("resultId", "00");
                resultMap.put("user", sysuser);
                resultMap.put("token", token.toString());
                resStr = JSON.toJSONString(resultMap);//返回toekn和用戶信息
    }catch(Exception e){
        Map<String, Object> resultMap = new HashMap<String, Object>();
                resultMap.put("resultId", "01");
                resultMap.put("resultMsg", e.getMessage());
                resStr = JSON.toJSONString(resultMap);//返回異常
    }

    return resStr;
}

RestfulSession,這個(gè)類中的靜態(tài)參數(shù)主要就是用來緩存正在登錄中的用戶的token與對(duì)應(yīng)的session

package com.tmri.framework.bean;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import com.tmri.share.frm.bean.UserSession;
public class RestfulSession{
    private static Map<String,UserSession> session=new HashMap<String,UserSession>(10000);//最多放一萬個(gè)用戶信息
    private static Map<String,String> clients=new HashMap<String,String>();
    public static UserSession getSession(String sessionId){
        return session.get(sessionId);
    }
    public static void setSession(String sessionId,UserSession clientUser){
        String yhdh=clientUser.getYhdh();
        String token=clients.get(yhdh);
        if(StringUtils.isNotEmpty(token)){
            session.remove(token);
        }
        session.put(sessionId,clientUser);
        clients.put(clientUser.getYhdh(),sessionId);
    }
    public static void renewal(String sessionId){
        session.get(sessionId).setScdlsj(new Date().getTime()+“”);
    }
}

二、token的調(diào)用
登錄后每次向后臺(tái)的請(qǐng)求都要帶上這個(gè)token值。如果移動(dòng)端規(guī)定時(shí)間(暫時(shí)定義為半小時(shí))內(nèi)沒有向后臺(tái)發(fā)起請(qǐng)求,該token作廢,后臺(tái)返回token超時(shí)的提示。說到這里,明眼人也看出來了,其實(shí)這個(gè)機(jī)制也是模仿J2EE的session機(jī)制。

以下是Android端登錄后向后臺(tái)發(fā)起訪問的代碼,一定要帶著token:

String creatUrl = "http://"+ip+":"+port+"/test/be/test.do?method=mytest"+"&token="+token;

OkHttpClientManager.ResultCallback cb = new OkHttpClientManager.ResultCallback<String>() {
        @Override
        public void onError(Request request, Exception e) {
                ToastUtil.showToastMsgError(TestActivity.this, "回應(yīng)服務(wù)器失敗");
        }

        @Override
        public void onResponse(String response) {
                JSONObject returnJson = JSONObject.parseObject(response);
                String resultId = returnJson.get("resultId").toString();

                String resultMsg = "";
                if(resultId.equals("00")){
                        resultMsg = "提交結(jié)果成功";
                        ToastUtil.showToastMsgError(TestActivity.this, resultMsg);
                }
                else if(resultId.equals("98")) // 會(huì)話過期
                {
                        relogin("當(dāng)前連接已過期,是否重新登陸?");
                }else{
                        //tasklist.clear();
                        resultMsg = "提交結(jié)果失?。?quot;+returnJson.get("resultMsg").toString();
                        ToastUtil.showToastMsgError(TestActivity.this, resultMsg);
                }
        }
};
OkHttpClientManager.getInstance().getAsyn(creatUrl,cb);

訪問的時(shí)候除了加入白名單的url,其他請(qǐng)求都要經(jīng)過攔截器的過濾,攔截器要判斷這次的請(qǐng)求是移動(dòng)端訪問(帶token的),還是一般的網(wǎng)頁(yè)訪問,有報(bào)錯(cuò)的話返回的東西也不一樣,移動(dòng)端訪問報(bào)錯(cuò)的話返回的是定義好格式的json字符串,而網(wǎng)頁(yè)訪問的話返回的一般是報(bào)錯(cuò)頁(yè)面(其實(shí),如果web端用前端框架的話,也可以是定義好格式的json字符串)。
以下是后臺(tái)的攔截器中的代碼:

Long timeout = (long) 1800000;//超時(shí)時(shí)間,30min
UserSession userSession;
String token = request.getParameter("token");
if(StrUtil.checkBN(token)){
    // 有token,接口訪問
    boolean flag=false;
    try{
        userSession=RestfulSession.getSession(token);
        if(userSession!=null){
            String currentURL=request.getServletPath();
            if(!userSession.getMenuList().contains(currentURL+"?method="+request.getParameter("method"))){
                sendRedirectJSON(request,response,"該用戶沒有權(quán)限");
                return false;
            }
            Calendar now=Calendar.getInstance();
            if(now.getTime().getTime()-Long.parseLong(userSession.getScdlsj())<timeout){// 如果該用戶最后訪問時(shí)間在30分鐘以內(nèi)
                flag=true;// 允許訪問
                RestfulSession.renewal(token);//重置該次登錄的session計(jì)時(shí)
            }else{
                sendRedirectJSON(request,response,"已超時(shí)");
                return false;
            }
        }
    }catch(Exception e){
        sendRedirectJSON(request,response,"請(qǐng)重新登錄");
    }
    if(!flag){
        sendRedirectJSON(request,response,"未登錄");
        return false;
    }else{
        return true;
    }
}else{
    //正常網(wǎng)頁(yè)訪問
    userSession=(UserSession)request.getSession().getAttribute("userSession");
    if(userSession==null){
        sendRedirect(request,response);
        return false;
    }

    String url="";
    if(StrUtil.checkBN(request.getParameter("method"))){
        url=handler.getClass().getName().substring(handler.getClass().getName().lastIndexOf(".")+1,handler.getClass().getName().length())+"."+request.getParameter("method");
    }else{
        url=handler.getClass().getName().substring(handler.getClass().getName().lastIndexOf(".")+1,handler.getClass().getName().length());
    }
    HashMap<String,String> rights=userSession.getRights();
    if(rights==null){//沒有權(quán)限
        sendRedirect(request,response);
        return false;
    }else{
        if(rights.containsKey(url)){
            return true;
        }else{//沒有權(quán)限
            sendRedirect(request,response);
            return false;
        }
    }
}

關(guān)于J2EE下怎樣模仿token機(jī)制就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI