This commit is contained in:
ran.shang
2025-06-11 09:42:13 +08:00
commit 7e38b8d971
1935 changed files with 132836 additions and 0 deletions

View File

@@ -0,0 +1,224 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.newyetai.security.access.intercept;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.SecurityMetadataSource;
import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
import org.springframework.security.access.intercept.InterceptorStatusToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import com.newyetai.common.AlitaResult;
import com.newyetai.common.exception.BusinessException;
import com.newyetai.common.exception.util.Assert;
import com.newyetai.common.util.ResponseUtils;
import com.newyetai.common.util.UserContextHolder;
import com.newyetai.security.access.request.AuthDtoUtils;
import com.newyetai.security.expection.BadLoginException;
import com.newyetai.security.util.SecurityPropertyUtils;
import com.newyetai.security.util.SecurityUtils;
import com.newyetai.usercenter.user.constant.UserTypeEnum;
import com.newyetai.usercenter.user.login.service.UserLoginService;
import lombok.extern.slf4j.Slf4j;
/**
* 菜单安全拦截器
*
* @author on 2019-11-05
*/
@Slf4j
public class FilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {
// ~ Static fields/initializers
// =====================================================================================
private static final String FILTER_APPLIED =
"__spring_security_filterSecurityInterceptor_filterApplied_2";
public static final String AUTH_URL = "/sys_security_auth";
public static final String ERROR_URL = "/error";
// ~ Instance fields
// ================================================================================================
private FilterInvocationSecurityMetadataSource securityMetadataSource;
private boolean observeOncePerRequest = true;
// ~ Methods
// ========================================================================================================
/**
* Not used (we rely on IoC container lifecycle services instead)
*
* @param arg0 ignored
*
* @throws ServletException never thrown
*/
@Override
public void init(FilterConfig arg0) throws ServletException {}
/**
* Not used (we rely on IoC container lifecycle services instead)
*/
@Override
public void destroy() {}
/**
* Method that is actually called by the filter chain. Simply delegates to the
* {@link #invoke(FilterInvocation)} method.
*
* @param request the servlet request
* @param response the servlet response
* @param chain the filter chain
*
* @throws IOException if the filter chain fails
* @throws ServletException if the filter chain fails
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
FilterInvocation fi = new FilterInvocation(request, response, chain);
invoke(fi);
}
public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
return this.securityMetadataSource;
}
@Override
public SecurityMetadataSource obtainSecurityMetadataSource() {
return this.securityMetadataSource;
}
public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource newSource) {
this.securityMetadataSource = newSource;
}
@Override
public Class<?> getSecureObjectClass() {
return FilterInvocation.class;
}
private RequestMatcher authRequestMatcher = new AntPathRequestMatcher(AUTH_URL, "POST");
private UserLoginService userLoginService;
public void setUserLoginService(UserLoginService userLoginService) {
this.userLoginService = userLoginService;
}
public void invoke(FilterInvocation fi) throws IOException, ServletException {
if (fi.getRequestUrl().equals(ERROR_URL)) {
log.info("访问资源不存在");
throw new BadLoginException("访问资源不存在");
}
// 如果是其他系统,调用用户中心鉴权
// 如果是用户中心,其他系统鉴权路径,
HttpServletRequest request = fi.getRequest();
HttpServletResponse response = fi.getResponse();
// 外部系统调用用户中心鉴权
boolean authInvoke = authRequestMatcher.matches(request);
if (authInvoke) {
FilterInvocation authFilterInvocation = AuthDtoUtils.analy(request);
try {
userLoginService.checkActive(request);
InterceptorStatusToken token = super.beforeInvocation(authFilterInvocation);
ResponseUtils.printJson(response, AlitaResult.success());
return;
} catch (BadLoginException be) {
ResponseUtils.printJson(response, be.getResult());
} catch (Exception e) {
log.error("鉴权失败", e);
ResponseUtils.printJson(response,
AlitaResult.error(AlitaResult.LOGIN_ERROR_CODE, e.getMessage()));
}
return;
}
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
boolean isAnno = auth.isAuthenticated() && SecurityPropertyUtils.isAnon(request);
boolean isUnac = !isAnno && SecurityPropertyUtils.isUnac(request);
boolean hasLogin = UserContextHolder.getLoginUser() != null;
// 匿名路径 | 未激活路径且已登录 直接过
boolean isAllowed =
(request != null) && (request.getAttribute(FILTER_APPLIED) != null) && observeOncePerRequest
|| isAnno
|| (hasLogin && isUnac);
if (isAllowed) {
// filter already applied to this request and user wants us to observe
// once-per-request handling, so don't re-do security checking
fi.getChain().doFilter(request, response);
} else {
// 未登录 去登录
Assert.isTrue(hasLogin, new BadLoginException(AlitaResult.unLogin()));
// first time this request being called, so perform security checking
if (request != null && observeOncePerRequest) {
request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
}
InterceptorStatusToken token = null;
// 用户中心鉴权
userLoginService.checkActive(request);
token = super.beforeInvocation(fi);
if (token == null) {
// TODO token 为空,资源未被分配,又不在白名单(只要登录就可访问),默认无权访问
// throw AccessDeniedException ;
}
try {
fi.getChain().doFilter(request, response);
} finally {
super.finallyInvocation(token);
}
super.afterInvocation(token, null);
}
}
/**
* Indicates whether once-per-request handling will be observed. By default this is
* <code>true</code>, meaning the <code>FilterSecurityInterceptor</code> will only execute
* once-per-request. Sometimes users may wish it to execute more than once per request, such as
* when JSP forwards are being used and filter security is desired on each included fragment of
* the HTTP request.
*
* @return <code>true</code> (the default) if once-per-request is honoured, otherwise
* <code>false</code> if <code>FilterSecurityInterceptor</code> will enforce
* authorizations for each and every fragment of the HTTP request.
*/
public boolean isObserveOncePerRequest() {
return observeOncePerRequest;
}
public void setObserveOncePerRequest(boolean observeOncePerRequest) {
this.observeOncePerRequest = observeOncePerRequest;
}
}

View File

@@ -0,0 +1,66 @@
package com.newyetai.security.access.metadata;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.stereotype.Component;
import com.google.common.collect.Maps;
import com.newyetai.common.entity.BaseEntity;
import com.newyetai.security.access.provider.ResourceConfigAttributeProvider;
import com.newyetai.usercenter.authority.dto.PermissionQueryDTO;
import com.newyetai.usercenter.dto.Resource;
import lombok.RequiredArgsConstructor;
/**
* 资源安全元数据源
*
* @author on 2019-11-05
*/
@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class ResourceSecurityMetadataSource {
private final List<ResourceConfigAttributeProvider> providers;
public Collection<ConfigAttribute> getAttributes(Object object,
PermissionQueryDTO permissionQueryDTO) throws IllegalArgumentException {
if (!this.supports(object.getClass())) {
return Collections.emptyList();
}
Long resourceId = ((Resource) object).getId();
Collection<ConfigAttribute> attributes =
getComponentMap(object, permissionQueryDTO).get(resourceId);
return attributes == null ? Collections.emptyList() : attributes;
}
public Map<Long, Collection<ConfigAttribute>> getComponentMap(Object object,
PermissionQueryDTO permissionQueryDTO) {
AnnotationAwareOrderComparator.sort(providers);
Map<Long, Collection<ConfigAttribute>> componentMap = Maps.newLinkedHashMap();
providers.forEach(provider -> {
// 选择支持的提供者
if (!provider.supports(object.getClass())) {
return;
}
Map<Long, Collection<ConfigAttribute>> map = provider.provide(permissionQueryDTO);
if (map != null && !map.isEmpty()) {
componentMap.putAll(map);
}
});
return componentMap;
}
public boolean supports(Class<?> clazz) {
return Resource.class.isAssignableFrom(clazz);
}
}

View File

@@ -0,0 +1,76 @@
package com.newyetai.security.access.metadata;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map.Entry;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;
import com.newyetai.common.util.SpringContextHolder;
import com.newyetai.security.access.provider.FilterConfigAttributeProvider;
import com.newyetai.security.access.request.AuthDtoUtils;
/**
* 菜单安全元数据源
*
* @author on 2019-11-05
*/
@Component
public class UrlFilterInvocationSecurityMetadataSource
implements FilterInvocationSecurityMetadataSource {
@Autowired
private List<FilterConfigAttributeProvider> providers;
@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
/*Set<ConfigAttribute> allAttributes = new HashSet<ConfigAttribute>();
for (Map.Entry<RequestMatcher, Collection<ConfigAttribute>> entry : getRequestMap()
.entrySet()) {
allAttributes.addAll(entry.getValue());
}*/
return Collections.emptyList();
}
@Override
public Collection<ConfigAttribute> getAttributes(Object object) {
final HttpServletRequest request = ((FilterInvocation) object).getRequest();
Integer systemCode = AuthDtoUtils.getSystemCode(SpringContextHolder.getRequest());
return getAttributes(request, systemCode);
}
public Collection<ConfigAttribute> getAttributes(HttpServletRequest request, Integer systemCode) {
for (FilterConfigAttributeProvider provider : providers) {
for (Entry<String, Collection<ConfigAttribute>> entry : provider.provide(systemCode).entrySet()) {
if (new AntPathRequestMatcher("/" + entry.getKey(), null).matches(request)) {
return entry.getValue();
}
}
}
return Collections.emptyList();
}
@Override
public boolean supports(Class<?> clazz) {
return FilterInvocation.class.isAssignableFrom(clazz);
}
@Autowired
public void setProvider(List<FilterConfigAttributeProvider> providers) {
AnnotationAwareOrderComparator.sort(providers);
this.providers = providers;
}
}

View File

@@ -0,0 +1,24 @@
package com.newyetai.security.access.provider;
import java.util.Collection;
import java.util.Map;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.web.util.matcher.RequestMatcher;
import com.newyetai.usercenter.authority.dto.PermissionQueryDTO;
/**
* 访问菜单权限信息提供者
* 资源被谁配置列表(可扩展configAttribute,可以有role_(目前),resource_等)
*
* @author on 2019-11-05
*/
public interface FilterConfigAttributeProvider {
/**
* 提供菜单权限信息,以Map结构返回,Key为路径,<br>
* Value为对应的权限信息
*
* @return 权限信息
*/
Map<String, Collection<ConfigAttribute>> provide(Integer systemCode);
}

View File

@@ -0,0 +1,25 @@
package com.newyetai.security.access.provider;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
import com.newyetai.usercenter.dto.IUserDetail;
/**
* 授权信息提供者
* 人被分配角色列表(后面可扩展authority,可以有role_(目前),resource_等)
*
* @author on 2019-11-05
*/
public interface GrantedAuthorityProvider {
/**
* 提供授权权限信息
*
* @param userDetails 用户信息
* @return 授权信息
*/
Collection<? extends GrantedAuthority> provide(IUserDetail userDetails);
}

View File

@@ -0,0 +1,23 @@
package com.newyetai.security.access.provider;
import java.io.Serializable;
import org.springframework.security.access.ConfigAttribute;
/**
* 资源权限
*
* @author sr on 2020-09-04
* @param <K>
*/
public interface IConfigAttribute<K extends Serializable> extends ConfigAttribute {
/**
* 唯一标识
*
* @return
* @author sr on 2020-09-04
*/
K getKey();
}

View File

@@ -0,0 +1,15 @@
package com.newyetai.security.access.provider;
import java.io.Serializable;
/**
* 请求资源权限
*
* @author sr on 2020-09-07
* @param <K>
*/
public interface IUrlConfigAttribute<K extends Serializable> extends IConfigAttribute<K> {
String getUrl();
}

View File

@@ -0,0 +1,54 @@
package com.newyetai.security.access.provider;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import com.google.common.collect.Sets;
import com.newyetai.usercenter.authority.dto.PermissionQueryDTO;
/**
* 资源权限信息提供者
*
* @author on 2019-11-05
*/
public interface ResourceConfigAttributeProvider<K extends Serializable, T extends IConfigAttribute<K>> {
/**
* 提供资源权限信息
*
* @return 权限信息
*/
List<T> list(PermissionQueryDTO permissionQueryDTO);
/**
* 支持类型
*
* @param clazz
* @return
* @author sr on 2019-11-05
*/
boolean supports(Class<?> clazz);
/**
*
* @return
* @author sr on 2020-09-07
*/
default Map<K, Collection<T>> provide(PermissionQueryDTO permissionQueryDTO) {
return this.list(permissionQueryDTO)
.stream()
.collect(
Collectors.toMap(
IConfigAttribute::getKey, v -> {
Collection<T> values = Sets.newHashSet();
values.add(v);
return values;
},
(v1, v2) -> {
v1.addAll(v2);
return v1;
}));
}
}

View File

@@ -0,0 +1,42 @@
package com.newyetai.security.access.provider.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import com.newyetai.security.access.provider.ResourceConfigAttributeProvider;
import com.newyetai.usercenter.authority.dto.ComponentPermissionDTO;
import com.newyetai.usercenter.authority.dto.PermissionQueryDTO;
import com.newyetai.usercenter.authority.service.UcPermissionService;
import com.newyetai.usercenter.constants.SecurityConstants;
import com.newyetai.usercenter.resource.dto.ComponentDTO;
/**
* 默认组件权限信息提供者
*
* @author on 2019-11-05
*/
@Order(100)
@Component
public class ComponentConfigAttributeProvider
implements ResourceConfigAttributeProvider<Long, ComponentPermissionDTO> {
@Autowired
private UcPermissionService ucPermissionService;
@Override
public boolean supports(Class<?> clazz) {
return ComponentDTO.class.isAssignableFrom(clazz);
}
@Override
@Cacheable(cacheNames = SecurityConstants.CacheName.COMPONENT_ATTRIBUTE_MAP_CACHE_KEY,
key = SecurityConstants.CACHE_KEY_PERMISSION_ORG_SYSTEM)
public List<ComponentPermissionDTO> list(PermissionQueryDTO permissionQueryDTO) {
return ucPermissionService.listComponent(permissionQueryDTO);
}
}

View File

@@ -0,0 +1,42 @@
package com.newyetai.security.access.provider.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import com.newyetai.security.access.provider.ResourceConfigAttributeProvider;
import com.newyetai.usercenter.authority.dto.PermissionQueryDTO;
import com.newyetai.usercenter.authority.dto.UrlPermissionDTO;
import com.newyetai.usercenter.authority.service.UcPermissionService;
import com.newyetai.usercenter.constants.SecurityConstants;
import com.newyetai.usercenter.resource.dto.UrlDTO;
/**
* 默认菜单权限信息提供者
*
* @author on 2019-11-05
*/
@Component
@Order(100)
public class UrlConfigAttributeProvider
implements ResourceConfigAttributeProvider<Long, UrlPermissionDTO> {
@Autowired
private UcPermissionService ucPermissionService;
@Override
public boolean supports(Class<?> clazz) {
return UrlDTO.class.isAssignableFrom(clazz);
}
@Override
@Cacheable(cacheNames = SecurityConstants.CacheName.URL_ATTRIBUTE_MAP_CACHE_KEY,
key = SecurityConstants.CACHE_KEY_PERMISSION_ORG_SYSTEM)
public List<UrlPermissionDTO> list(PermissionQueryDTO permissionQueryDTO) {
return ucPermissionService.listUrl(permissionQueryDTO).getData();
}
}

View File

@@ -0,0 +1,60 @@
package com.newyetai.security.access.provider.impl;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.core.annotation.Order;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.stereotype.Component;
import com.newyetai.common.AlitaResult;
import com.newyetai.common.exception.util.Assert;
import com.newyetai.security.access.provider.FilterConfigAttributeProvider;
import com.newyetai.security.service.IPermissionSecurityService;
import com.newyetai.usercenter.authority.dto.PermissionQueryDTO;
import com.newyetai.usercenter.authority.dto.UrlPermissionDTO;
import com.newyetai.usercenter.constants.SecurityConstants;
import com.newyetai.usercenter.resource.enums.UrlTypeEnum;
/**
* 默认菜单权限信息提供者
*
* @author on 2019-11-05
*/
@Component
@Order(100)
public class UrlFilterConfigAttribueProvider implements FilterConfigAttributeProvider {
@Autowired
private IPermissionSecurityService iPermissionSecurityService;
@Override
@Cacheable(cacheNames = SecurityConstants.CacheName.URL_FILTER_ATTRIBUTE_MAP_CACHE_KEY,
key = SecurityConstants.CACHE_KEY_SYSTEM)
public Map<String, Collection<ConfigAttribute>> provide(
Integer systemCode) {
// 应用下所有授权信息
PermissionQueryDTO permissionQueryDTO =
PermissionQueryDTO.builder().systemCode(systemCode).build();
AlitaResult<List<UrlPermissionDTO>> result =
iPermissionSecurityService.listUrl(permissionQueryDTO);
Assert.isTrue(result.getSuccess(), "资源权限获取失败");
return result.getData().stream().filter(p -> StringUtils.isNotBlank(p.getLink())
&& UrlTypeEnum.INTERFACE.getType().toString().equals(p.getResourceType()))
.collect(Collectors.toMap(UrlPermissionDTO::getLink, v -> {
Collection<ConfigAttribute> values = new HashSet<ConfigAttribute>();
values.add(v);
return values;
}, (v1, v2) -> {
v1.addAll(v2);
return v1;
}));
}
}

View File

@@ -0,0 +1,40 @@
package com.newyetai.security.access.provider.impl;
import java.util.Collection;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;
import com.newyetai.common.AlitaResult;
import com.newyetai.common.exception.util.Assert;
import com.newyetai.security.access.provider.GrantedAuthorityProvider;
import com.newyetai.security.service.IRoleAllocationSecurityService;
import com.newyetai.usercenter.authority.dto.RoleAllocationDTO;
import com.newyetai.usercenter.constants.SecurityConstants;
import com.newyetai.usercenter.dto.IUserDetail;
/**
* 默认用户授权信息提供者
*
* @author on 2019-11-05
*/
@Component
public class UserGrantedAuthorityProvider implements GrantedAuthorityProvider {
@Autowired
private IRoleAllocationSecurityService iRoleAllocationSecurityService;
@Override
@Cacheable(cacheNames = SecurityConstants.CacheName.USER_GRANTED_AUTHORITY_CACHE_KEY,
key = SecurityConstants.CACHE_KEY_ORG_USER)
public Collection<? extends GrantedAuthority> provide(IUserDetail userDetails) {
AlitaResult<List<RoleAllocationDTO>> result =
iRoleAllocationSecurityService.findByUserId(userDetails.getId());
Assert.isTrue(result.getSuccess(), "用户权限获取失败");
return result.getData();
}
}

View File

@@ -0,0 +1,28 @@
package com.newyetai.security.access.request;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author sr on 2020-09-09
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AuthDTO implements Serializable{
/** **/
private static final long serialVersionUID = -6816336716189522975L;
private String url;
private String method;
private Integer systemCode;
}

View File

@@ -0,0 +1,58 @@
package com.newyetai.security.access.request;
import javax.servlet.http.HttpServletRequest;
import org.springframework.security.web.FilterInvocation;
import com.newyetai.common.util.EnvironmentUtils;
/**
* @author sr on 2020-09-10
*/
public abstract class AuthDtoUtils {
public static final String PARAM_URL = "url";
public static final String PARAM_METHOD = "method";
public static final String PARAM_SYSTEMCODE = "systemCode";
/**
* 转换request为认证对象
*
* @param request
* @return
* @author sr on 2020-09-10
*/
public static AuthDTO convert(HttpServletRequest request) {
return AuthDTO.builder().url(request.getServletPath()).method(request.getMethod())
.systemCode(EnvironmentUtils.getSystemCode()).build();
}
/**
* 根据请求对象解析成拦截器调用对象
*
* @param request
* @return
* @author sr on 2020-09-10
*/
public static FilterInvocation analy(HttpServletRequest request) {
return new FilterInvocation(request.getParameter(PARAM_URL),
request.getParameter(PARAM_METHOD));
}
/**
* 获取请求的应用标识
*
* @param request
* @return
* @author sr on 2020-09-10
*/
public static Integer getSystemCode(HttpServletRequest request) {
String systemCodeStr = null;
if (request == null || (systemCodeStr = request.getParameter(PARAM_SYSTEMCODE)) == null) {
return EnvironmentUtils.getSystemCode();
}
return Integer.valueOf(systemCodeStr);
}
}

View File

@@ -0,0 +1,76 @@
package com.newyetai.security.access.vote;
import java.util.Collection;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.vote.AbstractAccessDecisionManager;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import com.newyetai.security.config.SecurityProperties;
import com.newyetai.security.dto.SecurityUserDTO;
/**
* 默认访问决策管理器
*
* @author on 2019-11-05
*/
@Component
public class AccessDecisionManagerImpl extends AbstractAccessDecisionManager {
private List<AccessDecisionVoter<? extends Object>> decisionVoters;
@Autowired
public AccessDecisionManagerImpl(List<AccessDecisionVoter<? extends Object>> decisionVoters, SecurityProperties securityProperties) {
super(decisionVoters);
this.decisionVoters = decisionVoters;
this.setAllowIfAllAbstainDecisions(securityProperties.getAllowIfAllAbstainDecisions());
}
@SuppressWarnings({"rawtypes", "unchecked"})
@Override
public void decide(Authentication authentication, Object object,
Collection<ConfigAttribute> configAttributes)
throws AccessDeniedException, InsufficientAuthenticationException {
Object principal = authentication.getPrincipal();
if (principal instanceof SecurityUserDTO
&& ((SecurityUserDTO) principal).getSupeiror()) {
// 平台管理员放行
return;
}
int deny = 0;
if (!configAttributes.isEmpty()) {
for (AccessDecisionVoter voter : getDecisionVoters()) {
if (voter.supports(object.getClass())) {
int result = voter.vote(authentication, object, configAttributes);
if (logger.isDebugEnabled()) {
logger.debug("Voter: " + voter + ", returned: " + result);
}
switch (result) {
case AccessDecisionVoter.ACCESS_GRANTED:
return;
case AccessDecisionVoter.ACCESS_DENIED:
deny++;
break;
default:
break;
}
}
}
}
if (deny > 0) {
throw new AccessDeniedException(
messages.getMessage("AbstractAccessDecisionManager.accessDenied", "Access is denied"));
}
checkAllowIfAllAbstainDecisions();
}
}

View File

@@ -0,0 +1,100 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.newyetai.security.access.vote;
import java.util.Collection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.FilterInvocation;
import org.springframework.stereotype.Component;
import com.newyetai.security.service.GrantedAuthorityService;
import com.newyetai.usercenter.dto.IUserDetail;
import com.newyetai.usercenter.dto.Resource;
/**
* 资源角色投票器 重写RoleVoter,获取用户授权信息authorities方式更改
*
* @author on 2019-11-05
*/
@Component
public class ResourceRoleVoter implements AccessDecisionVoter<Object> {
@Autowired
private GrantedAuthorityService grantedAuthorityService;
private String rolePrefix = "ROLE_";
public String getRolePrefix() {
return rolePrefix;
}
public void setRolePrefix(String rolePrefix) {
this.rolePrefix = rolePrefix;
}
@Override
public boolean supports(ConfigAttribute attribute) {
if ((attribute.getAttribute() != null)
&& attribute.getAttribute().startsWith(getRolePrefix())) {
return true;
} else {
return false;
}
}
@Override
public boolean supports(Class<?> clazz) {
return FilterInvocation.class.isAssignableFrom(clazz) || Resource.class.isAssignableFrom(clazz);
}
@Override
public int vote(Authentication authentication, Object object,
Collection<ConfigAttribute> attributes) {
if (authentication == null) {
return ACCESS_DENIED;
}
int result = ACCESS_ABSTAIN;
Collection<? extends GrantedAuthority> authorities = extractAuthorities(authentication);
for (ConfigAttribute attribute : attributes) {
if (this.supports(attribute)) {
result = ACCESS_DENIED;
for (GrantedAuthority authority : authorities) {
if (attribute.getAttribute().equals(authority.getAuthority())) {
return ACCESS_GRANTED;
}
}
}
}
return result;
}
Collection<? extends GrantedAuthority> extractAuthorities(Authentication authentication) {
if (authentication.getPrincipal() instanceof IUserDetail) {
IUserDetail userDetails = (IUserDetail) authentication.getPrincipal();
return grantedAuthorityService.getGrantedAuthorities(userDetails);
}
return authentication.getAuthorities();
}
}