package com.kidgrow.authclient.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.kidgrow.authclient.properties.SecurityProperties;
import com.kidgrow.authclient.util.AuthUtils;
import com.kidgrow.common.constant.CommonConstant;
import com.kidgrow.common.context.ClientContextHolder;
import com.kidgrow.common.model.SysMenu;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.util.AntPathMatcher;
import java.util.List;
import java.util.stream.Collectors;
/**
* 石家庄喜高科技有限责任公司 版权所有 © Copyright 2020
*
* @Description: 请求权限判断默认service
* @Project:
* @CreateDate: Created in 2020/2/13 11:46
* @Author: liuke
*/
@Slf4j
public abstract class DefaultPermissionServiceImpl {
@Autowired
private SecurityProperties securityProperties;
private AntPathMatcher antPathMatcher = new AntPathMatcher();
/**
* 查询当前用户拥有的资源权限
* @param roleCodes 角色code列表,多个以','隔开
* @return
*/
public abstract List findMenuByRoleCodes(String roleCodes);
public boolean hasPermission(Authentication authentication, String requestMethod, String requestURI) {
// 前端跨域OPTIONS请求预检放行 也可通过前端配置代理实现
if (HttpMethod.OPTIONS.name().equalsIgnoreCase(requestMethod)) {
return true;
}
if (!(authentication instanceof AnonymousAuthenticationToken)) {
//判断是否开启url权限验证
if (!securityProperties.getAuth().getUrlPermission().getEnable()) {
return true;
}
//超级管理员admin不需认证
String username = AuthUtils.getUsername(authentication);
if (CommonConstant.ADMIN_USER_NAME.equals(username)) {
return true;
}
OAuth2Authentication auth2Authentication = (OAuth2Authentication)authentication;
//判断应用黑白名单
if (!isNeedAuth(auth2Authentication.getOAuth2Request().getClientId())) {
return true;
}
//判断不进行url权限认证的api,所有已登录用户都能访问的url
for (String path : securityProperties.getAuth().getUrlPermission().getIgnoreUrls()) {
if (antPathMatcher.match(path, requestURI)) {
return true;
}
}
List grantedAuthorityList = (List) authentication.getAuthorities();
if (CollectionUtil.isEmpty(grantedAuthorityList)) {
log.warn("角色列表为空:{}", authentication.getPrincipal());
return false;
}
//保存租户信息
String clientId = auth2Authentication.getOAuth2Request().getClientId();
// String tenantId="";
// //保存租户id,租户id根据业务尽进行替换
// switch (clientId){
// case "hospital":
// tenantId="1";
// break;
// case "webApp":
// tenantId="webApp";
// break;
// }
// TenantContextHolder.setTenant(tenantId);
ClientContextHolder.setClient(clientId);
String roleCodes = grantedAuthorityList.stream().map(SimpleGrantedAuthority::getAuthority).collect(Collectors.joining(", "));
List menuList = findMenuByRoleCodes(roleCodes);
/*
*需求:h端 没有进行配置url的通过,剩下的进行验证
*
*/
//根据h端进行验证
if("hospital".equals(clientId)){
if(!menuList.isEmpty()){
List collect = menuList.stream().map(SysMenu::getUrl).collect(Collectors.toList());
if(collect.contains(requestURI)){
for (SysMenu menu : menuList) {
if (StringUtils.isNotEmpty(menu.getUrl()) && antPathMatcher.match(menu.getUrl(), requestURI)) {
if (StrUtil.isNotEmpty(menu.getPathMethod())) {
if(!requestMethod.equalsIgnoreCase(menu.getPathMethod())){
continue;
}
return requestMethod.equalsIgnoreCase(menu.getPathMethod());
}
}
}
}else {
//不在配置menu集合里面的放行
return true;
}
}else{
return true;
}
}
for (SysMenu menu : menuList) {
if (StringUtils.isNotEmpty(menu.getUrl()) && antPathMatcher.match(menu.getUrl(), requestURI)) {
if (StrUtil.isNotEmpty(menu.getPathMethod())) {
if(!requestMethod.equalsIgnoreCase(menu.getPathMethod())){
continue;
}
return requestMethod.equalsIgnoreCase(menu.getPathMethod());
} else {
return true;
}
}
}
}
return false;
}
/**
* 判断应用是否满足白名单和黑名单的过滤逻辑
* @param clientId 应用id
* @return true(需要认证),false(不需要认证)
*/
private boolean isNeedAuth(String clientId) {
boolean result = true;
//白名单
List includeClientIds = securityProperties.getAuth().getUrlPermission().getIncludeClientIds();
//黑名单
List exclusiveClientIds = securityProperties.getAuth().getUrlPermission().getExclusiveClientIds();
if (includeClientIds.size() > 0) {
result = includeClientIds.contains(clientId);
} else if(exclusiveClientIds.size() > 0) {
result = !exclusiveClientIds.contains(clientId);
}
return result;
}
}