Redis单点登陆系统(SSO)
在分布式系统中,通过会有多个服务,我们登录了一个服务以后,再访问其它服务时,不想再登录,就需要有一套单独的认证系统,我们通常会称之为单点登录系统,在这套系统中提供一个认证服务器,服务完成用户身份认证,在一些中小型分布式系统中中,我们通常会借助redis存储用户的认证信息,例如:
关键代码实现
package com.jt;
import redis.clients.jedis.Jedis;
import java.util.UUID;
/**
* 基于redis的单点登录设计及实现
* 1)用户登录成功以后将登录状态等信息存储到redis
* 2)用户携带token去访问资源,资源服务器要基于token从redis查询用户信息
*/
public class SSODemo01 {
/**
* 执行登录认证,将来这样的业务要写到认证服务器
* @param username
* @param password
*/
static String doLogin(String username,String password){
//1.检验数据的合法性(判定用户名,密码是否为空,密码的长度,是否有数字字母特殊符号构成)
if(username==null||"".equals(username))
throw new IllegalArgumentException("用户不能为空");
//2.基于用户名查询用户信息,并判定密码是否正确
if(!"jack".equals(username))
throw new RuntimeException("此用户不存在");
if(!"123456".equals(password))
throw new RuntimeException("密码不正确");
//3.用户存在且密码正确,将用户信息写入到redis
Jedis jedis = JedisDataSource.getConnection();
String token= UUID.randomUUID().toString();
jedis.hset(token, "username", username);
jedis.hset(token, "permission", "sys:resource:create");
jedis.expire(token, 10);//设置key的有效时间
jedis.close();
//4.将token返回给客户端(将来使用response对象响应到客户端).
return token;
}
static String token;
/**
* 演示资源访问过程
* 1)允许匿名访问(无需登录)
* 2)登录后访问(认证通过了)
* 3)登录后必须有权限才可以访问
*/
static Object doGetResource(String token){
//1.校验token是否为空
if(token==null)
throw new IllegalArgumentException("请先登录");
//2.基于token查询redis数据,假如有对应数据说明用户登录了
//方式一Jedis jedis=new Jedis("192.168.126.128", 6379);
Jedis jedis = JedisDataSource.getConnection();
String username=jedis.hget(token, "username");
if(username==null)
throw new RuntimeException("登录超时,请重新登录");
String permission=jedis.hget(token, "permission");
jedis.close();
//3.检查用户是否有访问资源的权限,假如有则允许访问
if(!"sys:resource:create".equals(permission))
throw new RuntimeException("你没有权限访问这个资源");
//4.返回要访问的资源.
return "访问资源成功!";
}
public static void main(String[] args) {
//1.登录操作(用户身份认证)
token=doLogin("jack", "123456");
System.out.println(token);
//2.携带token访问资源服务器
Object result=doGetResource(token);
System.out.println(result);
}
}
简易投票系统
在很多系统中设计中,都会有一个活动设计,开启一个活动之前,可以对这个活动的支持力度先进行一个调查,例如基于这个活动设计一个投票系统,例如:
package com.jt;
import com.jt.JedisDataSource;
import redis.clients.jedis.Jedis;
import java.util.Set;
/**
* 基于某个活动的简易投票系统设计
* 1)投票数据存储到redis (key为活动id,多个用户id的集合)
* 2)同一个用户不能执行多次投票
* 3)具体业务操作(投票,获取总票数,检查是否投过票,取消投票,获取哪些人参与了投票)
*/
public class VoteDemo01 {
/**
* 获取哪些人执行了这个活动的投票
* @param activityId
* @return
*/
static Set<String> doGetMembers(String activityId){
//1.建立连接
Jedis jedis = JedisDataSource.getConnection();
//2.获取当前活动的总票数
Set<String> smembers = jedis.smembers(activityId);
//3.释放资源
jedis.close();
return smembers;
}
/**
* 获取指定活动的投票总数
* @param activityId
* @return
*/
static Long doCount(String activityId){
//1.建立连接
Jedis jedis = JedisDataSource.getConnection();
//2.获取当前活动的总票数
Long count=jedis.scard(activityId);
//3.释放资源
jedis.close();
return count;
}
/**
* 执行投票操作
* @param activityId
* @param userId
*/
static void doVote(String activityId,String userId){
//1.建立连接
Jedis jedis = JedisDataSource.getConnection();
//2.执行投票
//2.1检查是否投过票
Boolean flag = jedis.sismember(activityId, userId);
//2.2执行投票或取消投票
if(flag){
//假如已经投过票,再投票就取消投票
jedis.srem(activityId, userId);
}else{
//没有投过票则执行投票
jedis.sadd(activityId, userId);
}
//3.释放资源
jedis.close();
}
public static void main(String[] args) {
String activityId="101";
String userId1="1";
String userId2="2";
String userId3="3";
//执行投票动作
doVote(activityId, userId1);
doVote(activityId, userId2);
doVote(activityId, userId3);
//获取投票的总票数
Long aLong = doCount(activityId);
System.out.println("投票总数:"+aLong);
//获取参与投票的成员
Set<String> members= doGetMembers(activityId);
System.out.println("投票人数:"+members);
}
}