Sign in

通过位运算来判断权限

比如在系统中拥有4种黑名单,分别是禁止登录、禁止留言、禁止发帖、和禁止下单。现在在用户发起某种操作时,就要判断该用户是否在黑名单中。

如果我们每次都在一个用户发起请求的时候去黑名单中查询是否存在这个用户,这未免有些愚蠢。也会对数据库造成比较大的压力。那如果直接把黑名单缓存到Redis的话,一是如果黑名单中人很多那就不太合适了,二是如果黑名单中有增删用户,那么整个缓存都需要更新。

所以我们采取缓存每个用户的权限状态来实现,四种权限状态用四位数字来标识,0为不在黑名单内,1为在黑名单内。

比如,一个用户的标识为0001,则这位用户被禁止下单,如果标识为0010,则这位用户被禁止发帖。

首先定义每一位所代表的权限类型:

// 是否禁止下单,二进制第1位,0表示否,1表示是
public static final int BAN_ORDER = 1 << 0; // 0001

// 是否禁止发帖,二进制第2位,0表示否,1表示是
public static final int BAN_POSTING = 1 << 1; // 0010

// 是否禁止留言,二进制第3位,0表示否,1表示是
public static final int BAN_LEAVE_MESSAGE = 1 << 2; // 0100

// 是否禁止登录,二进制第4位,0表示否,1表示是
public static final int BAN_LOGIN = 1 << 3; // 1000

在一个用户首次被判断权限时,我们查出这个用户在黑名单中的记录,取出他被禁止的类型,分别进行判断,得出一个用户的权限标识放入缓存中。

List<Byte> banTypes = userBanLists.stream().map(UserBanList::getBanType).collect(Collectors.toList());
int userBanFlag = 0;
if(banTypes.contains(BanTypeEnum.ORDER.getCode().byteValue())) {
userBanFlag |= BAN_ORDER;
}
if(banTypes.contains(BanTypeEnum.POSTING.getCode().byteValue())) {
userBanFlag |= BAN_POSTING;
}
if(banTypes.contains(BanTypeEnum.LEAVE_MESSAGE.getCode().byteValue())) {
userBanFlag |= BAN_LEAVE_MESSAGE;
}
if(banTypes.contains(BanTypeEnum.LOGIN.getCode().byteValue())) {
userBanFlag |= BAN_LOGIN;
}

这样在使用时直接取出用户标识,方便根据需要来判断是否在黑名单中了。

public boolean isUserBan(String userId, Integer banType) {

try {
int userBanFlag = BaseInfoCache.getUserBanFlag(userId);

if (ObjectUtils.isEmpty(userBanFlag)) {
return false;
}
if (banType.equals(BanTypeEnum.ORDER.getCode())) {
return (userStatusFlag & BAN_ORDER) == BAN_ORDER;
}
if (banType.equals(BanTypeEnum.POSTING.getCode())) {
return (userStatusFlag & BAN_POSTING) == BAN_POSTING;
}
if (banType.equals(BanTypeEnum.LEAVE_MESSAGE.getCode())) {
return (userStatusFlag & BAN_LEAVE_MESSAGE) == BAN_LEAVE_MESSAGE);
}
if (banType.equals(BanTypeEnum.LOGIN.getCode())) {
return (userStatusFlag & BAN_LOGIN) == BAN_LOGIN;
}
} catch (Exception e) {
log.error("judge user ban type is error", e);
}
return false;

}

另外在更改一个用户的权限时(将一个用户添加/移出黑名单时),把这个用户的缓存清掉就可以了,不影响其他用户。

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store