单点登陆大概逻辑
=============================查询部分==================================
1.取出Cookie
2.判断Cookie中是否有CSESSIONID
3.有,直接使用
4:没有,创建一个CSESSIONID,并保存到COOKIE中,
同时,把此COOKIe写回浏览器 使用此生成的CSESSIONID
5.设置 存活时间 -1(关闭页面)
6.设置路径 /
7.设置跨域
8.以CSESSIONID:NAME为key获取value
9.value不为null,以CSESSIONID:NAME为key,超时时间为value存入redis,
刷新超时时间,返回success
10.value为null,返回fail
=============================登陆部分==================================
1.判断账户密码的准确性
2.重复查询部分1-7
3.以CSESSIONID:NAME为key,超时时间为value存入redis,设置超时时间
==============================备注=====================================
CSESSIONID=UUID去除-
Jedis jedis = jedisPool.getResource();
jedis.close();
如果是使用连接池的形式,这个并非真正的close,而是把连接放回连接池中
复制代码
接口权限认证AOP
ReentrantLock保证线程安全/分布式可以用分布式锁
@Around环绕方式
lock.lock();
(ProceedingJoinPoint)pjp.proceed(args);token失败修改一个参数即可
lock.unlock();
=======================ReentrantLock(重入锁)============================
private Lock lock = new ReentrantLock();
private Condition condition=lock.newCondition();
线程1
lock.lock();
condition.await();释放了锁
线程2
lock.lock();
condition.signal();线程1继续跑
特别的:condition对象的signal只对本condition对象的await生效,
而object的notify()随机,两者的wait都释放锁,thread的sleep不释放
ReentrantReadWriteLock读写锁
lock.readLock().lock();
lock.readLock().unlock();
lock.writeLock().lock();
lock.writeLock().unlock();
多线程异步读,同步写
复制代码
redis分布式锁
场景一:C0操作超时了,但它还持有着锁,C1和C2读取lock.foo检查时间戳,先后发现超时了。
C1 发送DEL lock.foo
C1 发送SETNX lock.foo 并且成功了。
C2 发送DEL lock.foo
C2 发送SETNX lock.foo 并且成功了。
这样一来,C1,C2都拿到了锁!问题大了!
场景二:C3发送SETNX lock.foo 想要获得锁,由于C0还持有锁,所以Redis返回给C3一个0
C3发送GET lock.foo 以检查锁是否超时了,如果没超时,则等待或重试。
反之,如果已超时,C3通过下面的操作来尝试获得锁:
GETSET lock.foo <current Unix time + lock timeout + 1>
通过GETSET,C3拿到的时间戳如果仍然是超时的,那就说明,C3如愿以偿拿到锁了。
如果在C3之前,有个叫C4的客户端比C3快一步执行了上面的操作,那么C3拿到的时间戳是个未超时的值,
这时,C3没有如期获得锁,需要再次等待或重试。留意一下,尽管C3没拿到锁,
但它改写了C4设置的锁的超时值,不过这一点非常微小的误差带来的影响可以忽略不计。
Jedis jedis = jedisPool.getResource();
//setNx加锁
long now = System.currentTimeMillis();
boolean result = jedis.setnx(lockName, String.valueOf(now + expire * 1000)) == 1;
if (!result) {
//防止死锁的容错
String timestamp = jedis.get(lockName);
//检查锁是否超时了,如果没超时,则等待或重试
if (timestamp != null && Long.parseLong(timestamp) < now) {
//不通过del方法来删除锁。而是通过同步的getSet
String oldValue = jedis.getSet(lockName, String.valueOf(now + expire));
if (oldValue != null && oldValue.equals(timestamp)) {
//到的时间戳如果仍然是超时的,那就说明,C1如愿以偿拿到锁了
result = true;
jedis.expire(lockName, expire);
}
}
}
if (result) {
jedis.expire(lockName, expire);
}
//从源码可以分析得到,如果是使用连接池的形式,这个并非真正的close,而是把连接放回连接池中
jedis.close();
return result;
高版本的set命令也可以搞定。
复制代码