首頁 > 軟體

Redis妙用之儲存使用者token問題

2023-03-07 06:03:22

Redis 儲存使用者token

在設計類似電商的系統時,一個常見的需求是每個頁面都需要攜帶登入使用者資訊。

常見的解決方法有兩種:

  • 使用cookie儲存
  • 使用JWT儲存

但如果系統中使用了Redis快取,那麼還可以有第三種解決方案–將使用者token快取在Redis中。

登陸時生成一個token存入Redis

//生成一個token物件,儲存在redis中
redisTemplate.opsForHash().put("token","user",user);

在每個頁面生成時,提供token

//以JSON字串形式返回token
@RequestMapping(value = "/getToken",method = RequestMethod.GET)
@ResponseBody
public User getToken(){
    User user = (User) redisTemplate.opsForHash().get("token", "user");
    return user;
}
//傳送ajax請求,獲取token
function get_token(){
    $.ajax({
        url:"getToken",
        type:"GET",
        dataType:"JSON",
        success:function(result){
            //將返回的使用者資訊儲存在token中
            var token = result;
            //列印登入使用者
            console.log(token);
            //列印登入使用者的id
            console.log(token.id);
            document.getElementById('username').innerText = "使用者名稱:"+token.username;
        }
    });
}

登出時,刪除token

//登出
@RequestMapping("/logout")
public String logout(){
    redisTemplate.opsForHash().delete("token","user");
    return "/login";
}

Redis 處理token問題

java—基於redis處理token  

首先明確token:token是用來登入後進行前後端互動使用者資訊的一種處理方式,主要有兩種方式,一種是基於session進行儲存,一種是基於redis儲存,本文只討論基於redis做使用者資訊處理。  

使用者登入之後的每次資訊互動,如果需要傳遞使用者資訊,尤其是使用者id之類的,每次都去查詢資料庫顯然是不明智的,我們可以在登入後在redis建立一個空間用來儲存使用者資訊,之後每次需要使用者資訊的時候我們就從redis中取用。

首先建立RedisUtil

@Component

public class RedisUtil {

    @Autowired
    private RedisTemplate redisTemplate;   //key-value是物件的

    //判斷是否存在key
    public boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }

    //從redis中獲取值
    public Object get(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    //向redis插入值
    public boolean set(final String key, Object value) {
        boolean result = false;
        try {
            redisTemplate.opsForValue().set(key, value);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    //向redis插入值帶過期時間 單位:分鐘
    public boolean set(final String key, Object value, long time) {
        boolean result = false;
        try {
            redisTemplate.opsForValue().set(key, value, time, TimeUnit.MINUTES);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    //redis刪除值
    public boolean del(final String key) {
        return redisTemplate.delete(key);
    }

    //批次刪除某個欄位開始的key
    public long batchDel(String key) {
        Set<String> set = redisTemplate.keys(key + "*");
        return redisTemplate.delete(set);
    }

}

建立RedisUtil之後就是向redis中存值,此時需要注意,我們的key是需要提前和前端商量好,用哪一個欄位名,當前端請求時要將key放在header中傳遞過來,值是第一次登陸後經過加密處理返回給前端的,而我們拿到header資訊後就需要先解密value,將value作為key去拿使用者資訊。

@Component
public class UserUtil {
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private HttpServletRequest request;

    /**
     * 後臺管理的登入id
     *
     * @return
     */
    public JsonResult getUser() {
        String header = request.getHeader("#與前端約定的統一欄位#");
        //解密
        String decrypt = DESUtil.decrypt(header);
        if (!redisUtil.hasKey(decrypt))return JsonResult.error("未登入");
        User user = null;
        try {
            user = (User) redisUtil.get(decrypt);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (decrypt == null) return JsonResult.error("許可權不足");
        return JsonResult.success(user);
    }
}

當我們需要取用時

        JsonResult jsonResult = userUtil.getUser();
        if (jsonResult.getCode() != 1) return jsonResult;
        //強轉成物件。此處不用擔心強轉失敗,因為存入的時候就是物件儲存,只不過為了複用,存的是object型別
        User user= (User) jsonResult.getData();
        return JsonResult.success(#service層#);
    }

以上就是基於redis的token處理,個人使用習慣不一樣,方式可能不同,但是原理大同小異,一般來說,使用者資訊少的用session儲存就可以,大一點的用redis。

總結

這些僅為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com