前面弄了那么多,都是单独的模块。现在我们需要把用户和权限通过角色关联起来。
1、角色的权限列表更新操作
public void changeRoleAcls(int roleId, List aclIdList) {
//取出当前角色已分配的权限ID
List originAclIdList = sysRoleAclMapper.getAclIdListByRoleIdList(Lists.newArrayList(roleId));
//判断下当前的originAclIdList 是否与 传进了的aclIdList相同
//1.先判断下长度是否相等
if (originAclIdList.size() == aclIdList.size()) {
//用set存起来
Set originAclIdSet = Sets.newHashSet(originAclIdList);
Set aclIdSet = Sets.newHashSet(aclIdList);
//移出权限
originAclIdSet.removeAll(aclIdSet);
if (CollectionUtils.isEmpty(originAclIdSet)) {
//空,代表两个相同,不跟新
return;
}
}
//2.不相等则做更新操作
updateRoleAcls(roleId, aclIdList);
saveRoleAclLog(roleId, originAclIdList, aclIdList);
}
@Transactional
public void updateRoleAcls(int roleId, List aclIdList) {
//先删除原来权限
sysRoleAclMapper.deleteByRoleId(roleId);
if (CollectionUtils.isEmpty(aclIdList)) {
return;
}
List roleAclList = Lists.newArrayList();
for(Integer aclId : aclIdList) {
SysRoleAcl roleAcl = SysRoleAcl.builder().roleId(roleId).aclId(aclId).operator(RequestHolder.getCurrentUser().getUsername())
.operateIp(IpUtil.getRemoteIp(RequestHolder.getCurrentRequest())).operateTime(new Date()).build();
roleAclList.add(roleAcl);
}
//批量插入
sysRoleAclMapper.batchInsert(roleAclList);
}
1、根据roleId查user:查出拥有这个角色的用户列表
//根据roleId查user
public List getListByRoleId(int roleId) {
//1.获取userIdlist
List userIdList = sysRoleUserMapper.getUserIdListByRoleId(roleId);
if (CollectionUtils.isEmpty(userIdList)) {
return Lists.newArrayList();
}
//2.通过idlist获取userlist
return sysUserMapper.getByIdList(userIdList);
}
2、如果角色的权限改变了,那么对应拥有该角色的用户权限也要改变想·
//如果角色的权限改变了,那么对应拥有该角色的用户权限也要改变
public void changeRoleUsers(int roleId, List userIdList) {
//1.获取原本的userIdList
List originUserIdList = sysRoleUserMapper.getUserIdListByRoleId(roleId);
//2.是否相同,不同就跟新
if (originUserIdList.size() == userIdList.size()) {
//用set存起来
Set originAclIdSet = Sets.newHashSet(originUserIdList);
Set aclIdSet = Sets.newHashSet(userIdList);
//移出权限
originAclIdSet.removeAll(aclIdSet);
if (CollectionUtils.isEmpty(originAclIdSet)) {
//空,代表两个相同,不跟新
return;
}
}
//2.不相等则做更新操作
updateRoleUsers(roleId, userIdList);
saveRoleUserLog(roleId, originUserIdList, userIdList);
}
@Transactional
void updateRoleUsers(int roleId, List userIdList) {
sysRoleUserMapper.deleteByRoleId(roleId);
if (CollectionUtils.isEmpty(userIdList)) {
return;
}
List roleUserList = Lists.newArrayList();
for (Integer userId : userIdList) {
SysRoleUser roleUser = SysRoleUser.builder().roleId(roleId).userId(userId).operator(RequestHolder.getCurrentUser().getUsername())
.operateIp(IpUtil.getRemoteIp(RequestHolder.getCurrentRequest())).operateTime(new Date()).build();
roleUserList.add(roleUser);
}
sysRoleUserMapper.batchInsert(roleUserList);
}
//(1)获取当前用户权限列表
public List getCurrentUserAclList() {
//1.拿到当前用户的ID
int userId = RequestHolder.getCurrentUser().getId();
//2.通过id去查权限列表
return getUserAclList(userId);
}
//(1).2:通过id去查权限列表
public List getUserAclList(int userId) {
//如果是超级管理员,返回所有权限
if (isSuperAdmin()) {
return sysAclMapper.getAll();
}
//否则,通过UserId查角色Id列表:一个角色id有多个权限,一个用户id有多个角色id
List userRoleIdList = sysRoleUserMapper.getRoleIdListByUserId(userId);
if (CollectionUtils.isEmpty(userRoleIdList)) {
return Lists.newArrayList();
}
//列表不为空,通过 角色ID列表 查询角色拥有的 权限ID集合
List userAclIdList = sysRoleAclMapper.getAclIdListByRoleIdList(userRoleIdList);
if (CollectionUtils.isEmpty(userAclIdList)) {
return Lists.newArrayList();
}
//通过权限ID集合去查权限
return sysAclMapper.getByIdList(userAclIdList);
}
//(2) 获取当前角色所拥有权限列表
public List getRoleAclList(int roleId) {
//通过一个roleiId组一个roleId列表,通过列表去查权限列表
List aclIdList = sysRoleAclMapper.getAclIdListByRoleIdList(Lists.newArrayList(roleId));
if (CollectionUtils.isEmpty(aclIdList)) {
return Lists.newArrayList();
}
return sysAclMapper.getByIdList(aclIdList);
}
public boolean isSuperAdmin() {
// 这里是我自己定义了一个假的超级管理员规则,实际中要根据项目进行修改
// 可以是配置文件获取,可以指定某个用户,也可以指定某个角色
SysUser sysUser = RequestHolder.getCurrentUser();
if (sysUser.getUsername().contains("admin")) {
return true;
}
return false;
}
//***是否有权限访问URL
public boolean hasUrlAcl(String url) {
//是否为超级管理员
if (isSuperAdmin()) {
return true;
}
List aclList = sysAclMapper.getByUrl(url);
if (CollectionUtils.isEmpty(aclList)) {
return true;
}
List userAclList = getCurrentUserAclListFromCache();
Set userAclIdSet = userAclList.stream().map(acl -> acl.getId()).collect(Collectors.toSet());
boolean hasValidAcl = false;
// 规则:只要有一个权限点有权限,那么我们就认为有访问权限
for (SysAcl acl : aclList) {
// 判断一个用户是否具有某个权限点的访问权限
if (acl == null || acl.getStatus() != 1) { // 权限点无效
continue;
}
hasValidAcl = true;
if (userAclIdSet.contains(acl.getId())) {
return true;
}
}
if (!hasValidAcl) {
return true;
}
return false;
}
public List getCurrentUserAclListFromCache() {
int userId = RequestHolder.getCurrentUser().getId();
String cacheValue = sysCacheService.getFromCache(CacheKeyConstants.USER_ACLS, String.valueOf(userId));
//缓存中没有
if (StringUtils.isBlank(cacheValue)) {
//数据库取
List aclList = getCurrentUserAclList();
if (CollectionUtils.isNotEmpty(aclList)) {
sysCacheService.saveCache(JsonMapper.obj2String(aclList), 600, CacheKeyConstants.USER_ACLS, String.valueOf(userId));
}
return aclList;
}
return JsonMapper.string2Obj(cacheValue, new TypeReference>() {
});
}
}
1、首先设置一个白名单:
某些请求路径不需要拦截:
exclusionUrls
/sys/user/noAuth.page,/login.page
读取配置文件中的URL,设置白名单
String exclusionUrls = filterConfig.getInitParameter("exclusionUrls");
2、不在白名单里的都进行拦截,若没有权限,做友好提示
//权限过滤
@Slf4j
public class AclControlFilter implements Filter {
//定义全局变量set
private static Set exclusionUrlSet = Sets.newConcurrentHashSet();
private final static String noAuthUrl = "/sys/user/noAuth.page";
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//读取配置文件中的URL,设置白名单
String exclusionUrls = filterConfig.getInitParameter("exclusionUrls");
//String --- List
List exclusionUrlList = Splitter.on(",").trimResults().omitEmptyStrings().splitToList(exclusionUrls);
//List -- Set
exclusionUrlSet = Sets.newConcurrentHashSet(exclusionUrlList);
exclusionUrlSet.add(noAuthUrl);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
String servletPath = request.getServletPath();
Map requestMap = request.getParameterMap();
//路径在白名单中,不拦截
if (exclusionUrlSet.contains(servletPath)) {
filterChain.doFilter(servletRequest, servletResponse);
return;
}
//取当前登录用户
SysUser sysUser = RequestHolder.getCurrentUser();
//用户没登陆,设置无权限
if (sysUser == null) {
log.info("someone visit {}, but no login, parameter:{}", servletPath, JsonMapper.obj2String(requestMap));
noAuth(request, response);
return;
}
//从spring上下文中取bean,通过SysCoreService的方法来判断是否有权限访问这个URL
SysCoreService sysCoreService = ApplicationContextHelper.popBean(SysCoreService.class);
if (!sysCoreService.hasUrlAcl(servletPath)) {
log.info("{} visit {}, but no permission, parameter:{}", JsonMapper.obj2String(sysUser), servletPath, JsonMapper.obj2String(requestMap));
noAuth(request, response);
return;
}
filterChain.doFilter(servletRequest, servletResponse);
return;
}
//无权限访问处理方法
private void noAuth(HttpServletRequest request, HttpServletResponse response) throws IOException {
String servletPath = request.getServletPath();
//json请求
if (servletPath.endsWith(".json")) {
JsonData jsonData = JsonData.fail("没有访问权限,如需要访问,请联系管理员");
response.setHeader("Content-Type", "application/json");
response.getWriter().print(JsonMapper.obj2String(jsonData));
return;
//无权限访问跳转页面
} else {
clientRedirect(noAuthUrl, response);
return;
}
}
private void clientRedirect(String url, HttpServletResponse response) throws IOException{
response.setHeader("Content-Type", "text/html");
response.getWriter().print("\n"
+ "\n" + "\n" + "\n"
+ "跳转中... \n" + "\n" + "\n" + "跳转中,请稍候...\n" + "\n" + "\n" + "\n");
}
@Override
public void destroy() {
}
}
//保存角色与权限点的关系
@RequestMapping("/changeAcls.json")
@ResponseBody
public JsonData changeAcls(
@RequestParam("roleId") int roleId,
@RequestParam(value = "aclIds", required = false, defaultValue = "") String aclIds) {
List aclIdList = StringUtil.splitToListInt(aclIds);
sysRoleAclService.changeRoleAcls(roleId, aclIdList);
return JsonData.success();
}
//保存角色与用户的关系
@RequestMapping("/changeUsers.json")
@ResponseBody
public JsonData changeUsers(
@RequestParam("roleId") int roleId,
@RequestParam(value = "userIds", required = false, defaultValue = "") String userIds) {
//把UserId转为list
List userIdList = StringUtil.splitToListInt(userIds);
sysRoleUserService.changeRoleUsers(roleId, userIdList);
return JsonData.success();
}
//加载角色用户数据
@RequestMapping("/users.json")
@ResponseBody
public JsonData users(@RequestParam("roleId") int roleId) {
//通过roleId获取Userlist
List selectedUserList = sysRoleUserService.getListByRoleId(roleId);
//获取所有的user,然后减去前面获取的,就剩下没有获取的
List allUserList = sysUserService.getAll();
List unselectedUserList = Lists.newArrayList();
//优化for循环
Set selectedUserIdSet =
selectedUserList.stream().map(sysUser -> sysUser.getId()).collect(Collectors.toSet());
//如果是有效的并且在未选中的列表中就添加
for(SysUser sysUser : allUserList) {
if (sysUser.getStatus() == 1 && !selectedUserIdSet.contains(sysUser.getId())) {
unselectedUserList.add(sysUser);
}
}
/*当选择的用户的状态已经无效就不展示,使用流式过滤
selectedUserList = selectedUserList.stream().filter(sysUser -> sysUser.getStatus() != 1).collect(Collectors.toList());
*/
Map> map = Maps.newHashMap();
map.put("selected", selectedUserList);
map.put("unselected", unselectedUserList);
return JsonData.success(map);
}