App接口之Token令牌實現

《App接口之Token令牌實現》
轉載請注明來自 傻小孩b_移動開發(fā)http://www.itdecent.cn/users/d388bcf9c4d3)喜歡的可以關注我,不定期總結文章!您的支持是我的動力哈!

1、目的

眾所周知,在web端中,Token(令牌)只是作為防止用戶重復提交表單的作用而存在。但是對于App客戶端而言,Token卻充當著另一種角色,類似現實生活中代表每個人的角色認證、或者類似瀏覽器cookie代表你訪問網站的角色認證。前提,在有用戶系統(tǒng)的應用中,在每次訪問接口的時候,為了避免接口裸露被被無止境的請求攻擊,往往我們會利用一種機制,過濾一切非應用用戶端的非合法請求。首先我們不可能每次利用賬號密碼作為我們的過濾標準(會存在被抓包密碼泄露風險),因此便有
Token(令牌)的存在。即在存在這里的Token是指在指定有效時間內可以代表用戶角色,具有請求接口的權限。

當然,這里有開發(fā)者會提問,為什么不適用session。理論上是可以的,只是如果是有接觸過這部分的移動開發(fā)者,session本地是不好處理的,并且完全依賴
session,會被黑客截取后模擬請求,依然會存在被攻擊的風險。

2、實現思路

這里我不做加密方式選擇的舉例,這里只是做了簡單的做了不可逆的MD5加密方式(賬號+時間戳)。首先web框架是利用(spring + struct2 + mybatis),簡單說明下實現思路:

1、用戶登錄。請求登錄接口,如果賬號密碼核對正確,會根據賬號和時間戳進行Md5加密生成Token

2、服務端雙向保存token。服務端根據有效時間內生成對應的token之后,服務端雙向保存了Memcache中(
Memcache 是一種分布式緩存存儲機制,這里我就不詳細說明了),最后通過登錄接口返回Token信息至客戶端中
3、客戶端保存返回Token。
客戶端通過登錄接口成功返回的token,保存的內存中,在每次請求接口都要攜帶這個token,進行接口請求。

具體思路圖如下所示:

token_1.png

token_2.png

3、案例

(1)登錄接口實現

    /**
     * 用戶登錄
     * @throws IOException 
     */
    public void login() throws IOException{
        
        System.out.println("- AppUserManagerAction -" + "login");
        
        String token = TokenUtils.setToken(testAccount);
        System.out.println("賬號 " + testAccount + "生成的token:"+token);
        
        JSONObject json = new JSONObject();
        json.put("result", "0");
        json.put("reason", "用戶");
        json.put("token", token);
        
        this.getResponse().setContentType("text/plain");
        this.getResponse().setCharacterEncoding("UTF-8");
        this.getResponse().getWriter().write(json.toString());
        this.getResponse().getWriter().flush();
    }

(2)token生成

    /**
     * 為了登陸 或 刷新 Token 生成對應token
     */
    public static String setToken(String account){
        
        String token = generateToken(account);
        
        // 存儲正反向
        MemcacheManager.set(account + TOKEN_MARKER, token,TOKEN_VAILD_TIME);
        MemcacheManager.set(token,account + TOKEN_MARKER,TOKEN_VAILD_TIME);

        return token;
    }

(3)struct2 請求攔截

首先在接口請求中,為了對token進行驗證,這里是直接在
struct2中寫了一個攔截器對請求接口用戶Token的驗證,有疑問的可以自己谷歌搜索下struct2自定義攔截器


/**
 * Token 攔截器 用于檢測Token是否過去,過期直接不執(zhí)行Action
 * @author wsy
 *
 */
public class TokenInterceptor extends AbstractInterceptor {
    

    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        
        System.out.println("-- TokenInterceptor --");
        
        Object action = invocation.getAction();
        if (action instanceof MngUserAction || action instanceof AppUserManagerAction) {
            
            if (invocation.getProxy().getActionName().equals("login")) {
                System.out.println("-- TokenInterceptor -- " + "login 不需要攔截");
                return invocation.invoke();
            }
          
        }
        
        // 取得請求相關的ActionContext實例  
        ActionContext actionContext = invocation.getInvocationContext();  
        
        HttpServletRequest request = (HttpServletRequest) actionContext.get(StrutsStatics.HTTP_REQUEST);
        HttpServletResponse response = (HttpServletResponse)actionContext.get(org.apache.struts2.StrutsStatics.HTTP_RESPONSE);  
        
        if (TokenUtils.isVaild(request)) {
            System.out.println("token 有效");
            invocation.invoke();
        }else{
            System.out.println("token 過期");
            
            JSONObject json = new JSONObject();
            json.put("result", "002");
            json.put("reason", "Token 過期");

            response.setContentType("text/plain");
            response.setCharacterEncoding("UTF-8");
            response.getWriter().write(json.toString());
            response.getWriter().flush();
        }
        
        
        return null;
    }

}

(4)struct2 配置

    <!-- struts 設置默認配置 -->
    <package name="struts-shop" extends="struts-default">
        <interceptors>
            <!-- 默認攔截器 -->
            <interceptor name="authority" class="employee.utils.TokenInterceptor" />

            <!-- 攔截器棧 -->
            <interceptor-stack name="myStack">
                <interceptor-ref name="defaultStack" />
                <interceptor-ref name="authority" />
            </interceptor-stack>

        </interceptors>
        <default-interceptor-ref name="myStack" />
    </package>

    <package name="/employee/application/action" namespace="/employee/application/action"
        extends="struts-shop">

        <action name="login" class="employee.application.action.AppUserManagerAction"
            method="login" />
        <action name="getPersonInfo" class="employee.application.action.AppUserManagerAction"
            method="getPersonInfo"/>

    </package>

4、總結

當然在正式平臺,加密方式不會這么簡單,具體可以看下
http://blog.csdn.net/jack85986370/article/details/51362278 這篇文章,非對稱加密就有很強的加密方式,通過公鑰與私鑰進行信息加密。有什么問題可以聯系筆者,歡迎技術交流哈~

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現,斷路器,智...
    卡卡羅2017閱讀 136,695評論 19 139
  • 1. 微服務架構介紹 1.1 什么是微服務架構? 形像一點來說,微服務架構就像搭積木,每個微服務都是一個零件,并使...
    靜修佛緣閱讀 6,824評論 0 39
  • 本文目錄:一、單體應用 VS 微服務二、微服務常見安全認證方案三、JWT介紹四、OAuth 2.0 介紹五、思考總...
    挨踢的懶貓閱讀 18,107評論 5 29
  • 轉載本文需注明出處:微信公眾號EAWorld,違者必究。 本文目錄: 一、單體應用 VS 微服務 二、微服務常見安...
    72a1f772fe47閱讀 8,746評論 3 25
  • 無論任何時候,都不要對一個人太好,因為你終有一天會發(fā)現,對一個人好,時間久了,那個人是會習慣的,然后把這一切看作是...
    你倒是發(fā)個光呀閱讀 147評論 0 0

友情鏈接更多精彩內容