com.github.xujiaji.mk.security.admin.config.RbacAuthorityService Maven / Gradle / Ivy
The newest version!
package com.github.xujiaji.mk.security.admin.config;
import cn.hutool.core.util.StrUtil;
import com.github.xujiaji.mk.common.base.Consts;
import com.github.xujiaji.mk.common.base.Status;
import com.github.xujiaji.mk.security.entity.MkSecPermission;
import com.github.xujiaji.mk.security.entity.MkSecRole;
import com.github.xujiaji.mk.security.mapper.MkSecPermissionMapper;
import com.github.xujiaji.mk.security.mapper.MkSecRoleMapper;
import com.github.xujiaji.mk.security.vo.UserPrincipal;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import com.github.xujiaji.mk.security.exception.SecurityException;
/**
*
* 动态路由认证
*
*/
@Component
public class RbacAuthorityService {
@Autowired
private MkSecRoleMapper mkSecRoleMapper;
@Autowired
private MkSecPermissionMapper mkSecPermissionMapper;
@Autowired
private RequestMappingHandlerMapping mapping;
public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
checkRequest(request);
Object userInfo = authentication.getPrincipal();
boolean hasPermission = false;
if (userInfo instanceof UserDetails) {
UserPrincipal principal = (UserPrincipal) userInfo;
Long secUserId = principal.getSecUserId();
List roles = mkSecRoleMapper.selectBySecUserId(secUserId);
List roleIds = roles.stream()
.map(MkSecRole::getId)
.collect(Collectors.toList());
List permissions = mkSecPermissionMapper.selectByRoleIdList(roleIds);
//获取资源,前后端分离,所以过滤页面权限,只保留按钮权限
List btnPerms = permissions.stream()
// 过滤页面权限
.filter(permission -> Objects.equals(permission.getType(), Consts.BUTTON))
// 过滤 URL 为空
.filter(permission -> StrUtil.isNotBlank(permission.getUrl()))
// 过滤 METHOD 为空
.filter(permission -> StrUtil.isNotBlank(permission.getMethod()))
.collect(Collectors.toList());
for (MkSecPermission btnPerm : btnPerms) {
AntPathRequestMatcher antPathMatcher = new AntPathRequestMatcher(btnPerm.getUrl(), btnPerm.getMethod());
if (antPathMatcher.matches(request)) {
hasPermission = true;
break;
}
}
return hasPermission;
} else {
return false;
}
}
/**
* 校验请求是否存在
*
* @param request 请求
*/
private void checkRequest(HttpServletRequest request) {
// 获取当前 request 的方法
String currentMethod = request.getMethod();
Multimap urlMapping = allUrlMapping();
for (String uri : urlMapping.keySet()) {
// 通过 AntPathRequestMatcher 匹配 url
// 可以通过 2 种方式创建 AntPathRequestMatcher
// 1:new AntPathRequestMatcher(uri,method) 这种方式可以直接判断方法是否匹配,因为这里我们把 方法不匹配 自定义抛出,所以,我们使用第2种方式创建
// 2:new AntPathRequestMatcher(uri) 这种方式不校验请求方法,只校验请求路径
AntPathRequestMatcher antPathMatcher = new AntPathRequestMatcher(uri);
if (antPathMatcher.matches(request)) {
if (!urlMapping.get(uri)
.contains(currentMethod)) {
throw new SecurityException(Status.HTTP_BAD_METHOD);
} else {
return;
}
}
}
throw new SecurityException(Status.REQUEST_NOT_FOUND);
}
/**
* 获取 所有URL Mapping,返回格式为{"/test":["GET","POST"],"/sys":["GET","DELETE"]}
*
* @return {@link ArrayListMultimap} 格式的 URL Mapping
*/
private Multimap allUrlMapping() {
Multimap urlMapping = ArrayListMultimap.create();
// 获取url与类和方法的对应信息
Map handlerMethods = mapping.getHandlerMethods();
handlerMethods.forEach((k, v) -> {
// 获取当前 key 下的获取所有URL
Set url = k.getPatternsCondition()
.getPatterns();
RequestMethodsRequestCondition method = k.getMethodsCondition();
// 为每个URL添加所有的请求方法
url.forEach(s -> urlMapping.putAll(s, method.getMethods()
.stream()
.map(Enum::toString)
.collect(Collectors.toList())));
});
return urlMapping;
}
}