基于Guava Cache内存缓存实现的token验证

    最近做毕设,学习用到了Guava Cache和token机制,做个总结。

    功能需求是这样的,在客户端用户登录时忘记密码,需要找回密码,通过正确输入找回密码答案来访问服务端的修改密码接口。为了防止恶意用户来直接访问修改密码接口,在调用验证答案接口后采用token机制来验证身份,并用Guava Cache做一个定时的token来保证安全性。

理解token机制

 

    什么是token

    token的意思是“令牌”,是服务端生成的一串字符串,作为客户端进行请求的一个标识。当用户第一次登录后,服务器生成一个token并将此token返回给客户端,以后客户端只需带上这个token前来请求数据即可,无需再次带上用户名和密码。

 

    身份认证概述

    由于HTTP是一种没有状态的协议,它并不知道是谁访问了我们的应用。这里把用户看成是客户端,客户端使用用户名还有密码通过了身份验证,不过下次这个客户端再发送请求时候,还得再验证一下。
通用的解决方法就是,当用户请求登录的时候,如果没有问题,在服务端生成一条记录,在这个记录里可以说明登录的用户是谁,然后把这条记录的id发送给客户端,客户端收到以后把这个id存储在cookie里,下次该用户再次向服务端发送请求的时候,可以带上这个cookie,这样服务端会验证一下cookie里的信息,看能不能在服务端这里找到对应的记录,如果可以,说明用户已经通过了身份验证,就把用户请求的数据返回给客户端。
以上所描述的过程就是利用session,那个id值就是sessionid。我们需要在服务端存储为用户生成的session,这些session会存储在内存,磁盘,或者数据库。

    基于token机制的身份认证

    使用token机制的身份验证方法,在服务器端不需要存储用户的登录记录。大概的流程:

客户端使用用户名和密码请求登录。服务端收到请求,验证用户名和密码。验证成功后,服务端会生成一个token,然后把这个token发送给客户端。客户端收到token后把它存储起来,可以放在cookie或者Local Storage(本地存储)里。客户端每次向服务端发送请求的时候都需要带上服务端发给的token。服务端收到请求,然后去验证客户端请求里面带着token,如果验证成功,就向客户端返回请求的数据。

   Guava Cache

Guava Cache是单个应用运行时的本地缓存。它不把数据存放到文件或者外部服务器上。简单、强大、及轻量级。它不需要配置文件,使用起来和ConcurrentHashMap一样简单,而且能覆盖绝大多数使用cache的场景需求

   实例

    校验答案正确后,在service层来生成一个唯一token,一般可以使用mac地址,或者sessionId来生成token。因为token是可以被截获的,非常容易泄露,如果不进行加密,很容易被恶意拷贝并用来登录。所以一般会对token进行加密处理。

一般可以在存储的时候把token进行对称加密存储,用到的时候再解密,或者使用请求URL、时间戳、token三者合并,通过算法进行加密处理。两个一块用更安全。这里就简单利用UUID来实现生成唯一token

    

  String forgetToken = UUID.randomUUID().toString();

然后再把token存到本地Guava Cache内存缓存中,在响应对象中也把这个token封装起来响应给客户端。到时候用户改密,就可以传入该token实现token机制。

 TokenCache.setKey("Token_"+username,forgetToken);

Guava Cache实现

package com.lsmall.common;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/*
 * @Author Liang Shan
 * @Description token本地缓存,使用guava缓存实现
 * @Date 2018/6/1 17:28
 * @Version 1.0
 * */
public class TokenCache {
    //    创建logback的logger
    private static Logger logger = LoggerFactory.getLogger(TokenCache.class);
//    声明一个静态的内存块,guava里面的本地缓存
    private static LoadingCache<String, String> localcache =
        //构建本地缓存,调用链的方式 ,1000是设置缓存的初始化容量,maximumSize是设置缓存最大容量,当超过了最大容量,guava将使用LRU算法(最少使用算法),来移除缓存项
        //expireAfterAccess(12,TimeUnit.HOURS)设置缓存有效期为12个小时
        CacheBuilder.newBuilder().initialCapacity(1000).maximumSize(10000).expireAfterAccess(12,TimeUnit.HOURS)
        //build里面要实现一个匿名抽象类
                .build(new CacheLoader<String, String>() {
//                   这个方法是默认的数据加载实现,get的时候,如果key没有对应的值,就调用这个方法进行加载

                    @Override
                    public String load(String s) throws Exception {
//                        为什么要把return的null值写成字符串,因为到时候用null去.equal的时候,会报空指针异常
                        return "null";
                    }
                });

    /*
     * 添加本地缓存
     * */
    public static void setKey(String key, String value) {
        localcache.put(key, value);
    }

    /*
     * 得到本地缓存
     * */
    public static String getKey(String key) {
        String value = null;
        try {
            value= localcache.get(key);
            if ("null".equals(value)) {
                return  null;
            }
            return value;
        } catch (ExecutionException e) {
            logger.error("getKey()方法错误",e);
        }
        return null;
    }
}

Guava Cache的回收策略

有两种回收策略:

一种是基于容量的回收CacheBuilder.maximumSize(Long)。设置缓存最大容量,当超过最大容量,缓存将尝试回收最近没有使用或总体上很少使用的缓存项。

第二种定时回收

expireAfterAccess(long,TimeUnit):缓存项在给定时间内没有被读写访问,则回收。请注意这种缓存的回收顺序和基于大小回收一样。

  expireAfterWrite(long,TimeUnit):缓存项在给定时间内没有被写访问(创建或覆盖),则回收。如果认为缓存数据总是在固定时候后变的陈旧不可用,这种回收是可取的。

实例中用的是第一种策略,通过设置缓存最大容量,当超过了最大容量,guava将使用LRU算法来减少缓存项

 

LRU算法原理

LRU(Least recently used,最近最少使用的)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高。

最常见的实现是使用一个链表保存缓存数据:
1 新数据插入到链表头部
2 每当缓存命中(即缓存数据被访问),则将数据移到链表头部
3 当链表满的时候,将链表尾部的数据丢弃

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值