1. 程式人生 > >Springboot 實現api校驗和登入驗證

Springboot 實現api校驗和登入驗證

https://blog.csdn.net/qq_36085004/article/details/83348144

2018年10月24日 17:59:29  閱讀數:232

 

文章目錄

 

API校驗

場景

在前後端分離開發時,後端獲取資料就是通過非同步請求調我們的API介面,但是,如果我們不做安全處理,其他人也可以直接調我們的API,這會讓我們的資料洩露。因此,為了讓我們的API只能被我們允許的人呼叫,我們對我們的API進行安全處理,他人在呼叫我們的API時需要進行校驗,符合的才允許呼叫API。

實現思路

客戶端:
呼叫我們API的人需要用時間戳timestamp,隨機字串noncestr,請求引數以升序排列拼接成一個字串,並使用MD5進行加密生成一個簽名sign。
在傳送請求時,將timestamp, noncestr,sign傳送給後臺

後臺:
編寫一個攔截器,將所有的請求攔截。
在攔截器中進行請求校驗:
1,請求引數sign是否為空,為空返回false。
2,timestamp 加十分鐘(超過10分鐘請求過期)是否小於服務端當前時間戳,小於返回false。
3,後臺獲取所有引數,以同樣的規則拼接字串,使用MD5加密,得到一個簽名,用得到的簽名和請求傳來的簽名進行比較,相同則放行,不同返回false。

程式碼

攔截器:

<span style="color:rgba(0, 0, 0, 0.75)"><span style="color:#000000"><code class="language-Java">package com.xyy.edlp.intercepter;

import org.springframework.util.DigestUtils;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 * @Author: perkins
 */
public class ApiSignatureInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                             Object handler) throws Exception {
        Enumeration<String> paramNames = request.getParameterNames();
        String timestamp = request.getHeader("timestamp");

        long timestampDate = Long.valueOf(timestamp) + 1000*60*10;
        long currDate = System.currentTimeMillis();
        // 請求過期
        if (timestampDate < currDate) {
            response.setStatus(403);
            return false;
        }

        String noncestr = request.getHeader("noncestr");
        String signature = request.getParameter("sign");
        System.out.println(signature);

        if (signature == null) {
            response.setStatus(403);
            return false;
        }
        Map map = new HashMap();

        //獲取所有的請求引數
        while (paramNames.hasMoreElements()) {
            String paramName = paramNames.nextElement();
            String[] paramValues = request.getParameterValues(paramName);

            if (paramValues.length > 0) {
                String paramValue = paramValues[0];
                System.out.println(paramName);
                if (paramValue.length() != 0 && !"sign".equals(paramName)) {
                    map.put(paramName, paramValue);
                }
            }
        }

        Set setKey = map.keySet();
        Object[] keys = setKey.toArray();
        // 將請求引數升序排序
        Arrays.sort(keys);

        StringBuilder strBuilder = new StringBuilder();
        for (Object str : keys) {
            strBuilder.append(str.toString());
            strBuilder.append(map.get(str.toString()));
        }

        strBuilder.append("noncestr");
        strBuilder.append(noncestr);
        strBuilder.append("timestamp");
        strBuilder.append(timestamp);

        System.out.println(strBuilder.toString());
        String newSignature = DigestUtils.md5DigestAsHex(strBuilder.toString().getBytes()).toUpperCase();

        if (!signature.equals(newSignature)) {
            response.setStatus(403);
            return false;
        }
        return true;
    }
}

</code></span></span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79

攔截器註冊:

<span style="color:rgba(0, 0, 0, 0.75)"><span style="color:#000000"><code class="language-Java">@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry){
        registry.addInterceptor(new ApiSignatureInterceptor());
    }
}
</code></span></span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

登入token許可權驗證

場景

系統中,有的api必須使用者登陸了才能夠呼叫,因此,必須給這樣的api進行安全防護。

實現思路

1,客戶端呼叫登入介面,登入成功,使用JWT生成一個token,將token以UID—token鍵值對的形式存入redis,返回給客戶端一個token和UID。
2,建立一個攔截器,對需要登入許可權的介面進行攔截,判斷請求中是否有token,根據UID從redis中取出對應的token,對請求中的token進行驗證,然後再使用JWT驗證token,都沒問題放行,否則返回false。

程式碼

jwt生成token程式碼

<span style="color:rgba(0, 0, 0, 0.75)"><span style="color:#000000"><code class="language-java"><span style="color:#c678dd">package</span> com<span style="color:#999999">.</span>xyy<span style="color:#999999">.</span>edlp<span style="color:#999999">.</span>util<span style="color:#999999">;</span>


<span style="color:#c678dd">import</span> com<span style="color:#999999">.</span>auth0<span style="color:#999999">.</span>jwt<span style="color:#999999">.</span>JWT<span style="color:#999999">;</span>
<span style="color:#c678dd">import</span> com<span style="color:#999999">.</span>auth0<span style="color:#999999">.</span>jwt<span style="color:#999999">.</span>JWTVerifier<span style="color:#999999">;</span>
<span style="color:#c678dd">import</span> com<span style="color:#999999">.</span>auth0<span style="color:#999999">.</span>jwt<span style="color:#999999">.</span>algorithms<span style="color:#999999">.</span>Algorithm<span style="color:#999999">;</span>
<span style="color:#c678dd">import</span> com<span style="color:#999999">.</span>auth0<span style="color:#999999">.</span>jwt<span style="color:#999999">.</span>exceptions<span style="color:#999999">.</span>JWTDecodeException<span style="color:#999999">;</span>
<span style="color:#c678dd">import</span> com<span style="color:#999999">.</span>auth0<span style="color:#999999">.</span>jwt<span style="color:#999999">.</span>interfaces<span style="color:#999999">.</span>DecodedJWT<span style="color:#999999">;</span>

<span style="color:#c678dd">import</span> java<span style="color:#999999">.</span>io<span style="color:#999999">.</span>UnsupportedEncodingException<span style="color:#999999">;</span>
<span style="color:#c678dd">import</span> java<span style="color:#999999">.</span>util<span style="color:#999999">.</span>Date<span style="color:#999999">;</span>

<span style="color:#5c6370">/**
 * @Author: perkins
 */</span>
<span style="color:#c678dd">public</span> <span style="color:#c678dd">class</span> JwtUtil <span style="color:#999999">{</span>
    <span style="color:#c678dd">private</span> <span style="color:#c678dd">static</span> <span style="color:#c678dd">final</span> String encodeSecretKey <span style="color:#669900">=</span> <span style="color:#669900">"XX#$%()(#*!()!KL<><MQLMNQNQJQKsdfkjsdrow32234545fdf>?N<:{LWPW"</span><span style="color:#999999">;</span>

    <span style="color:#5c6370">/**
     * token過期時間
     */</span>
    <span style="color:#c678dd">private</span> <span style="color:#c678dd">static</span> <span style="color:#c678dd">final</span> <span style="color:#c678dd">long</span> EXPIRE_TIME <span style="color:#669900">=</span> <span style="color:#98c379">1000</span> <span style="color:#669900">*</span> <span style="color:#98c379">60</span> <span style="color:#669900">*</span> <span style="color:#98c379">60</span> <span style="color:#669900">*</span> <span style="color:#98c379">24</span> <span style="color:#669900">*</span> <span style="color:#98c379">7</span><span style="color:#999999">;</span>

    <span style="color:#5c6370">/**
     * 生成token
     * @return
     */</span>
    <span style="color:#c678dd">public</span> <span style="color:#c678dd">static</span> String <span style="color:#61aeee">createToken</span><span style="color:#999999">(</span>String account<span style="color:#999999">)</span> <span style="color:#999999">{</span>
        <span style="color:#c678dd">try</span> <span style="color:#999999">{</span>
            Date date <span style="color:#669900">=</span> <span style="color:#c678dd">new</span> Date<span style="color:#999999">(</span>System<span style="color:#999999">.</span><span style="color:#61aeee">currentTimeMillis</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#669900">+</span> EXPIRE_TIME<span style="color:#999999">)</span><span style="color:#999999">;</span>
            Algorithm algorithm <span style="color:#669900">=</span> Algorithm<span style="color:#999999">.</span><span style="color:#61aeee">HMAC256</span><span style="color:#999999">(</span>account <span style="color:#669900">+</span> encodeSecretKey<span style="color:#999999">)</span><span style="color:#999999">;</span>
            <span style="color:#c678dd">return</span> JWT<span style="color:#999999">.</span><span style="color:#61aeee">create</span><span style="color:#999999">(</span><span style="color:#999999">)</span>
                    <span style="color:#999999">.</span><span style="color:#61aeee">withExpiresAt</span><span style="color:#999999">(</span>date<span style="color:#999999">)</span>
                    <span style="color:#999999">.</span><span style="color:#61aeee">withClaim</span><span style="color:#999999">(</span><span style="color:#669900">"account"</span><span style="color:#999999">,</span> account<span style="color:#999999">)</span>
                    <span style="color:#999999">.</span><span style="color:#61aeee">sign</span><span style="color:#999999">(</span>algorithm<span style="color:#999999">)</span><span style="color:#999999">;</span>
        <span style="color:#999999">}</span> <span style="color:#c678dd">catch</span> <span style="color:#999999">(</span>UnsupportedEncodingException e<span style="color:#999999">)</span> <span style="color:#999999">{</span>
            <span style="color:#c678dd">return</span> null<span style="color:#999999">;</span>
        <span style="color:#999999">}</span>
    <span style="color:#999999">}</span>

    <span style="color:#5c6370">/**
     * 校驗token是否失效
     * @param token
     * @return
     */</span>
    <span style="color:#c678dd">public</span> <span style="color:#c678dd">static</span> <span style="color:#c678dd">boolean</span> <span style="color:#61aeee">checkToken</span><span style="color:#999999">(</span>String token<span style="color:#999999">,</span> String account<span style="color:#999999">)</span> <span style="color:#999999">{</span>
        <span style="color:#c678dd">try</span> <span style="color:#999999">{</span>
            Algorithm algorithm <span style="color:#669900">=</span> Algorithm<span style="color:#999999">.</span><span style="color:#61aeee">HMAC256</span><span style="color:#999999">(</span>account <span style="color:#669900">+</span> encodeSecretKey<span style="color:#999999">)</span><span style="color:#999999">;</span>
            JWTVerifier verifier <span style="color:#669900">=</span> JWT<span style="color:#999999">.</span><span style="color:#61aeee">require</span><span style="color:#999999">(</span>algorithm<span style="color:#999999">)</span>
                    <span style="color:#999999">.</span><span style="color:#61aeee">build</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
            DecodedJWT jwt <span style="color:#669900">=</span> verifier<span style="color:#999999">.</span><span style="color:#61aeee">verify</span><span style="color:#999999">(</span>token<span style="color:#999999">)</span><span style="color:#999999">;</span>
            <span style="color:#c678dd">return</span> <span style="color:#56b6c2">true</span><span style="color:#999999">;</span>
        <span style="color:#999999">}</span> <span style="color:#c678dd">catch</span> <span style="color:#999999">(</span>UnsupportedEncodingException e<span style="color:#999999">)</span> <span style="color:#999999">{</span>
            <span style="color:#c678dd">return</span> <span style="color:#56b6c2">false</span><span style="color:#999999">;</span>
        <span style="color:#999999">}</span>
    <span style="color:#999999">}</span>

    <span style="color:#5c6370">/**
     * 獲取使用者account
     * @param token
     * @return
     */</span>
    <span style="color:#c678dd">public</span> <span style="color:#c678dd">static</span> String <span style="color:#61aeee">getAccount</span><span style="color:#999999">(</span>String token<span style="color:#999999">)</span><span style="color:#999999">{</span>
        <span style="color:#c678dd">try</span> <span style="color:#999999">{</span>
            DecodedJWT jwt <span style="color:#669900">=</span> JWT<span style="color:#999999">.</span><span style="color:#61aeee">decode</span><span style="color:#999999">(</span>token<span style="color:#999999">)</span><span style="color:#999999">;</span>
            <span style="color:#c678dd">return</span> jwt<span style="color:#999999">.</span><span style="color:#61aeee">getClaim</span><span style="color:#999999">(</span><span style="color:#669900">"account"</span><span style="color:#999999">)</span><span style="color:#999999">.</span><span style="color:#61aeee">asString</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
        <span style="color:#999999">}</span> <span style="color:#c678dd">catch</span> <span style="color:#999999">(</span>JWTDecodeException e<span style="color:#999999">)</span> <span style="color:#999999">{</span>
            <span style="color:#c678dd">return</span> null<span style="color:#999999">;</span>
        <span style="color:#999999">}</span>
    <span style="color:#999999">}</span>

    <span style="color:#999999">}</span>

</code></span></span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73

攔截器程式碼:

<span style="color:rgba(0, 0, 0, 0.75)"><span style="color:#000000"><code class="language-Java">public class JwtInterceptor extends HandlerInterceptorAdapter {

    @Autowired
    RedisUtil redisUtil;

    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {
        String token = request.getHeader("Authorization");
        if (token == null) {
            response.setStatus(401);
            return false;
        }

        String account = JwtUtil.getAccount(token);
        String redisToken = redisUtil.get(RedisKey.TP_STORE_KEY + account);
        boolean isExpire = JwtUtil.checkToken(token, account);

        if (redisToken == null || redisToken != token || isExpire) {
            response.setStatus(401);
            return false;
        }
        return true;
    }
}
</code></span></span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

攔截器註冊:

<span style="color:rgba(0, 0, 0, 0.75)"><span style="color:#000000"><code class="language-Java">@Configuration
public class WebConfig implements WebMvcConfigurer {

   // 再攔截器中使用了RedisUtil bean類,但是攔截器執行實在spring容器bean初始化之前的
   // RedisUtil 將無法注入,為了解決該問題,將JwtInterceptor攔截器先配置為一個bean
   // 在註冊攔截器時,直接使用配置的bean
    @Bean
    public JwtInterceptor jwtInterceptor(){
        return new JwtInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry){
        registry.addInterceptor(jwtInterceptor())
                .addPathPatterns("/tp_store/logout");
    }
}
</code></span></span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

現在才知道,零基礎學習高階Java後,年薪可以這麼多! 
零基礎學IT選Java,易學、高薪、前景廣,100萬人才缺口,網際網路必備人才