使用场景
- 比如某个领导因故不能登录网站进行一些操作,他想把网站上的工作委托给他的秘书,但却不想把账号、密码告诉她。此时我们可以使用Shiro的RunAs功能,即允许一个用户假装成另一个用户的身份进行访问。
示例
- 示例基于第十六章,主要功能是用户、公司、角色和资源之间关系的调整,如修改用户所属公司、所有角色,资源所需权限、角色所有资源等。
- 数据库:新增user_runas表,映射原用户与代用户,必须有相应记录才能切换身份。
- 实体:新增UserRunAs类。
public class UserRunAs implements Serializable {
private Long fromUserId;//授予身份帐号A(老板)
private Long toUserId;//被授予身份帐号B(秘书)
}
- dao:新增RunAs增删查改方法。
- service:新增RunAs增删查改方法。
@Service("userRunAsService")
public class UserRunAsServiceImpl implements UserRunAsService {
@Autowired
private UserRunAsDao userRunAsDao;
/**
* @Author haien
* @Description 授予身份,实际就是新增记录
* @Date 2019/4/10
* @Param [fromUserId, toUserId]
* @return void
**/
@Override
public void grantRunAs(Long fromUserId, Long toUserId) {
userRunAsDao.grantRunAs(fromUserId, toUserId);
}
/**
* @Author haien
* @Description 回收身份,实际就是删除记录
* @Date 2019/4/10
* @Param [fromUserId, toUserId]
* @return void
**/
@Override
public void revokeRunAs(Long fromUserId, Long toUserId) {
userRunAsDao.revokeRunAs(fromUserId, toUserId);
}
/**
* @Author haien
* @Description 关系存在判断,实际就是查找
* @Date 2019/4/10
* @Param [fromUserId, toUserId]
* @return boolean
**/
@Override
public boolean exists(Long fromUserId, Long toUserId) {
return userRunAsDao.exists(fromUserId, toUserId);
}
/**
* @Author haien
* @Description 根据秘书查找其代理的老板
* @Date 2019/4/10
* @Param [toUserId]
* @return java.util.List<java.lang.Long>
**/
@Override
public List<Long> findFromUserIds(Long toUserId) {
return userRunAsDao.findFromUserIds(toUserId);
}
/**
* @Author haien
* @Description 根据老板查找其委托的秘书
* @Date 2019/4/10
* @Param [fromUserId]
* @return java.util.List<java.lang.Long>
**/
@Override
public List<Long> findToUserIds(Long fromUserId) {
return userRunAsDao.findToUserIds(fromUserId);
}
}
- controller:新增RunAs增删查改方法,真正实现身份切换。
//判断当前用户是否为代理老板
Subject subject = SecurityUtils.getSubject();
//当前用户是老板,但是个代理老板
if(subject.isRunAs()) {
//获取之前的身份信息,一个用户可以切换很多身份,之前的身份使用栈存储
String previousUsername =
(String)subject.getPreviousPrincipals().getPrimaryPrincipal();
//得到最近一个
}
- Subject.isRunAs(): 判断当前用户是否是代理得来的身份。
- Subject.getPreviousPrincipals():得到之前的身份,一个用户可多次切换身份,它们被存在栈中,栈顶为最近用过的身份。
@RequestMapping("/switchTo/{switchToUserId}")
public String switchTo(@CurrentUser User loginUser, //当前用户
@PathVariable("switchToUserId") Long switchToUserId, //要切换到的用户
RedirectAttributes redirectAttributes) {
//判断当前用户要切换的身份是否为自身
//查找目标用户的身份
User switchToUser = userService.findOne(switchToUserId);
//切换
subject.runAs(new SimplePrincipalCollection(switchToUser.getUsername(), ""));
}
- subject.runAs(PrincipalCollection, realmName): 切换到指定用户。
Subject subject = SecurityUtils.getSubject();
if(subject.isRunAs()) {
//切换回上一个身份;如果A切换到B,B又切换到C,那么需要执行两次才能回到A
subject.releaseRunAs();
}
subject.releaseRunAs():切换回上一个身份。
测试:
- 修改数据库,使admin的角色为超管,而zhang无角色,即zhang比admin低。
- 登录admin账号,点击切换身份,将身份授予用户zhang。
- 退出,登录账号zhang,点击切换身份,切换到admin,刷新当前页面,原本空白的菜单栏会出现all选项,因为拥有admin的权限了。