init
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user