添加基于路径的动态权限支持
This commit is contained in:
parent
167e2d6ce6
commit
f1bec5df7f
@ -0,0 +1,51 @@
|
||||
package com.macro.mall.security.component;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import org.springframework.security.access.AccessDecisionManager;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.authentication.InsufficientAuthenticationException;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* 动态权限决策管理器,用于判断用户是否有访问权限
|
||||
* Created by macro on 2020/2/7.
|
||||
*/
|
||||
public class DynamicAccessDecisionManager implements AccessDecisionManager {
|
||||
|
||||
@Override
|
||||
public void decide(Authentication authentication, Object object,
|
||||
Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
|
||||
// 当接口未被配置资源时直接放行
|
||||
if (CollUtil.isEmpty(configAttributes)) {
|
||||
return;
|
||||
}
|
||||
Iterator<ConfigAttribute> iterator = configAttributes.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
ConfigAttribute configAttribute = iterator.next();
|
||||
//将访问所需资源或用户拥有资源进行比对
|
||||
String needAuthority = configAttribute.getAttribute();
|
||||
for (GrantedAuthority grantedAuthority : authentication.getAuthorities()) {
|
||||
if (needAuthority.trim().equals(grantedAuthority.getAuthority())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new AccessDeniedException("抱歉,您没有访问权限");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(ConfigAttribute configAttribute) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(Class<?> aClass) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
package com.macro.mall.security.component;
|
||||
|
||||
import com.macro.mall.security.config.IgnoreUrlsConfig;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.access.SecurityMetadataSource;
|
||||
import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
|
||||
import org.springframework.security.access.intercept.InterceptorStatusToken;
|
||||
import org.springframework.security.web.FilterInvocation;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.PathMatcher;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 动态权限过滤器,用于实现基于路径的动态权限过滤
|
||||
* Created by macro on 2020/2/7.
|
||||
*/
|
||||
public class DynamicSecurityFilter extends AbstractSecurityInterceptor implements Filter {
|
||||
|
||||
@Autowired
|
||||
private DynamicSecurityMetadataSource dynamicSecurityMetadataSource;
|
||||
@Autowired
|
||||
private IgnoreUrlsConfig ignoreUrlsConfig;
|
||||
|
||||
@Autowired
|
||||
public void setMyAccessDecisionManager(DynamicAccessDecisionManager dynamicAccessDecisionManager) {
|
||||
super.setAccessDecisionManager(dynamicAccessDecisionManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
|
||||
HttpServletRequest request = (HttpServletRequest) servletRequest;
|
||||
FilterInvocation fi = new FilterInvocation(servletRequest, servletResponse, filterChain);
|
||||
//OPTIONS请求直接放行
|
||||
if(request.getMethod().equals(HttpMethod.OPTIONS.toString())){
|
||||
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
|
||||
return;
|
||||
}
|
||||
//白名单请求直接放行
|
||||
PathMatcher pathMatcher = new AntPathMatcher();
|
||||
for (String path : ignoreUrlsConfig.getUrls()) {
|
||||
if(pathMatcher.match(path,request.getRequestURI())){
|
||||
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
|
||||
return;
|
||||
}
|
||||
}
|
||||
//此处会调用AccessDecisionManager中的decide方法进行鉴权操作
|
||||
InterceptorStatusToken token = super.beforeInvocation(fi);
|
||||
try {
|
||||
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
|
||||
} finally {
|
||||
super.afterInvocation(token, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getSecureObjectClass() {
|
||||
return FilterInvocation.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecurityMetadataSource obtainSecurityMetadataSource() {
|
||||
return dynamicSecurityMetadataSource;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package com.macro.mall.security.component;
|
||||
|
||||
import cn.hutool.core.util.URLUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.web.FilterInvocation;
|
||||
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.PathMatcher;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 动态权限数据源,用于获取动态权限规则
|
||||
* Created by macro on 2020/2/7.
|
||||
*/
|
||||
public class DynamicSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
|
||||
|
||||
private static Map<String, ConfigAttribute> configAttributeMap = null;
|
||||
@Autowired
|
||||
private DynamicSecurityService dynamicSecurityService;
|
||||
|
||||
@PostConstruct
|
||||
public void loadDataSource() {
|
||||
configAttributeMap = dynamicSecurityService.loadDataSource();
|
||||
}
|
||||
|
||||
public void clearDataSource() {
|
||||
configAttributeMap.clear();
|
||||
configAttributeMap = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ConfigAttribute> getAttributes(Object o) throws IllegalArgumentException {
|
||||
if (configAttributeMap == null) this.loadDataSource();
|
||||
List<ConfigAttribute> configAttributes = new ArrayList<>();
|
||||
//获取当前访问的路径
|
||||
String url = ((FilterInvocation) o).getRequestUrl();
|
||||
String path = URLUtil.getPath(url);
|
||||
PathMatcher pathMatcher = new AntPathMatcher();
|
||||
Iterator<String> iterator = configAttributeMap.keySet().iterator();
|
||||
//获取访问该路径所需资源
|
||||
while (iterator.hasNext()) {
|
||||
String pattern = iterator.next();
|
||||
if (pathMatcher.match(pattern, path)) {
|
||||
configAttributes.add(configAttributeMap.get(pattern));
|
||||
}
|
||||
}
|
||||
// 未设置操作请求权限,返回空集合
|
||||
return configAttributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ConfigAttribute> getAllConfigAttributes() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(Class<?> aClass) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package com.macro.mall.security.component;
|
||||
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 动态权限相关业务类
|
||||
* Created by macro on 2020/2/7.
|
||||
*/
|
||||
public interface DynamicSecurityService {
|
||||
/**
|
||||
* 加载资源ANT通配符和资源对应MAP
|
||||
*/
|
||||
Map<String, ConfigAttribute> loadDataSource();
|
||||
}
|
@ -20,6 +20,8 @@ public class RestfulAccessDeniedHandler implements AccessDeniedHandler{
|
||||
public void handle(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
AccessDeniedException e) throws IOException, ServletException {
|
||||
response.setHeader("Access-Control-Allow-Origin", "*");
|
||||
response.setHeader("Cache-Control","no-cache");
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
response.setContentType("application/json");
|
||||
response.getWriter().println(JSONUtil.parse(CommonResult.forbidden(e.getMessage())));
|
||||
|
@ -1,9 +1,9 @@
|
||||
package com.macro.mall.security.config;
|
||||
|
||||
import com.macro.mall.security.component.JwtAuthenticationTokenFilter;
|
||||
import com.macro.mall.security.component.RestAuthenticationEntryPoint;
|
||||
import com.macro.mall.security.component.RestfulAccessDeniedHandler;
|
||||
import com.macro.mall.security.component.*;
|
||||
import com.macro.mall.security.util.JwtTokenUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
@ -14,6 +14,7 @@ import org.springframework.security.config.annotation.web.configurers.Expression
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
|
||||
|
||||
@ -23,6 +24,9 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic
|
||||
*/
|
||||
public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Autowired(required = false)
|
||||
private DynamicSecurityService dynamicSecurityService;
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity httpSecurity) throws Exception {
|
||||
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = httpSecurity
|
||||
@ -53,6 +57,10 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
// 自定义权限拦截器JWT过滤器
|
||||
.and()
|
||||
.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
|
||||
//有动态权限配置时添加动态权限校验过滤器
|
||||
if(dynamicSecurityService!=null){
|
||||
registry.and().addFilterBefore(dynamicSecurityFilter(), FilterSecurityInterceptor.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -97,4 +105,23 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
return new JwtTokenUtil();
|
||||
}
|
||||
|
||||
@ConditionalOnBean(name = "dynamicSecurityService")
|
||||
@Bean
|
||||
public DynamicAccessDecisionManager dynamicAccessDecisionManager() {
|
||||
return new DynamicAccessDecisionManager();
|
||||
}
|
||||
|
||||
|
||||
@ConditionalOnBean(name = "dynamicSecurityService")
|
||||
@Bean
|
||||
public DynamicSecurityFilter dynamicSecurityFilter() {
|
||||
return new DynamicSecurityFilter();
|
||||
}
|
||||
|
||||
@ConditionalOnBean(name = "dynamicSecurityService")
|
||||
@Bean
|
||||
public DynamicSecurityMetadataSource dynamicSecurityMetadataSource() {
|
||||
return new DynamicSecurityMetadataSource();
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user