IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> spring security url动态授权 -> 正文阅读

[Java知识库]spring security url动态授权


spring security url动态授权

????????

官网:https://docs.spring.io/spring-security/reference/servlet/appendix/faq.html#appendix-faq-dynamic-url-metadata

????????????????????????

????????????????????????????????????????

引入jar包

??????????????

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        ...
    </dependencies>

    ...

</project>

???????

????????????

????????????????????????????????????????

动态数据源

??????????????

FilterInvocationSecurityMetadataSource:获取数据源

public interface FilterInvocationSecurityMetadataSource extends SecurityMetadataSource {
}

???????????

SecurityMetadataSource

public interface SecurityMetadataSource extends AopInfrastructureBean {
    Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException;
                                //获取object对应的权限

    Collection<ConfigAttribute> getAllConfigAttributes();

    boolean supports(Class<?> clazz);
}

????????????

ConfigAttribute:权限属性

public interface ConfigAttribute extends Serializable {
    String getAttribute();
}

?????????????

?????????????

?SecurityConfig:attrib可用来设置权限值(admin、user等)

public class SecurityConfig implements ConfigAttribute {
    private final String attrib;

    public SecurityConfig(String config) {
        Assert.hasText(config, "You must provide a configuration attribute");
        this.attrib = config;
    }

    public boolean equals(Object obj) {
        if (obj instanceof ConfigAttribute) {
            ConfigAttribute attr = (ConfigAttribute)obj;
            return this.attrib.equals(attr.getAttribute());
        } else {
            return false;
        }
    }

    public String getAttribute() {
        return this.attrib;
    }

    public int hashCode() {
        return this.attrib.hashCode();
    }

    public String toString() {
        return this.attrib;
    }

    public static List<ConfigAttribute> createListFromCommaDelimitedString(String access) {
        return createList(StringUtils.commaDelimitedListToStringArray(access));
    }

    public static List<ConfigAttribute> createList(String... attributeNames) {
        Assert.notNull(attributeNames, "You must supply an array of attribute names");
        List<ConfigAttribute> attributes = new ArrayList(attributeNames.length);
        String[] var2 = attributeNames;
        int var3 = attributeNames.length;

        for(int var4 = 0; var4 < var3; ++var4) {
            String attribute = var2[var4];
            attributes.add(new SecurityConfig(attribute.trim()));
        }

        return attributes;
    }
}

????????????????

?????????????????????

????????????????????????????????????????

权限拦截器

????????????

AbstractSecurityInterceptor

public abstract class AbstractSecurityInterceptor implements InitializingBean, ApplicationEventPublisherAware, MessageSourceAware {
    protected final Log logger = LogFactory.getLog(this.getClass());
    protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
    private ApplicationEventPublisher eventPublisher;
    private AccessDecisionManager accessDecisionManager;
    private AfterInvocationManager afterInvocationManager;
    private AuthenticationManager authenticationManager = new AbstractSecurityInterceptor.NoOpAuthenticationManager();
    private RunAsManager runAsManager = new NullRunAsManager();
    private boolean alwaysReauthenticate = false;
    private boolean rejectPublicInvocations = false;
    private boolean validateConfigAttributes = true;
    private boolean publishAuthorizationSuccess = false;

    public AbstractSecurityInterceptor() {
    }


    public void afterPropertiesSet() {
    public void setRunAsManager(RunAsManager runAsManager) {
    public void setMessageSource(MessageSource messageSource) {
    public void setAlwaysReauthenticate(boolean alwaysReauthenticate) {
    public void setAuthenticationManager(AuthenticationManager newManager) {
    public void setRejectPublicInvocations(boolean rejectPublicInvocations) {
    public void setValidateConfigAttributes(boolean validateConfigAttributes) {
    public void setPublishAuthorizationSuccess(boolean publishAuthorizationSuccess) {
    public void setAccessDecisionManager(AccessDecisionManager accessDecisionManager) {
    public void setAfterInvocationManager(AfterInvocationManager afterInvocationManager) {
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {


    public boolean isAlwaysReauthenticate() {
    public boolean isRejectPublicInvocations() {
    public boolean isValidateConfigAttributes() {

    public AccessDecisionManager getAccessDecisionManager() {
    public AfterInvocationManager getAfterInvocationManager() {
    public AuthenticationManager getAuthenticationManager() {
    public RunAsManager getRunAsManager() {


    public abstract Class<?> getSecureObjectClass();
    public abstract SecurityMetadataSource obtainSecurityMetadataSource();

    protected void finallyInvocation(InterceptorStatusToken token) {
    protected InterceptorStatusToken beforeInvocation(Object object) {
    protected Object afterInvocation(InterceptorStatusToken token, Object returnedObject) {


    private Authentication authenticateIfRequired() {
    private void publishEvent(ApplicationEvent event) {
    private void validateAttributeDefs(Collection<ConfigAttribute> attributeDefs) {
    private void attemptAuthorization(Object object, Collection<ConfigAttribute> attributes, Authentication authenticated) {
    private void credentialsNotFound(String reason, Object secureObject, Collection<ConfigAttribute> configAttribs) {


*********
静态内部类:NoOpAuthenticationManager

    private static class NoOpAuthenticationManager implements AuthenticationManager {
        private NoOpAuthenticationManager() {
        }

        public Authentication authenticate(Authentication authentication) throws AuthenticationException {
            throw new AuthenticationServiceException("Cannot authenticate " + authentication);
        }
    }
}

?????????????

???????????

FilterSecurityInterceptor

public class FilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {
    private static final String FILTER_APPLIED = "__spring_security_filterSecurityInterceptor_filterApplied";
    private FilterInvocationSecurityMetadataSource securityMetadataSource;
    private boolean observeOncePerRequest = true;

    public FilterSecurityInterceptor() {
    }

    public void init(FilterConfig arg0) {
    }

    public void destroy() {
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        this.invoke(new FilterInvocation(request, response, chain));
    }

    public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
        return this.securityMetadataSource;
    }

    public SecurityMetadataSource obtainSecurityMetadataSource() {
        return this.securityMetadataSource;
    }

    public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource newSource) {
        this.securityMetadataSource = newSource;
    }

    public Class<?> getSecureObjectClass() {
        return FilterInvocation.class;
    }

    public void invoke(FilterInvocation filterInvocation) throws IOException, ServletException {
        if (this.isApplied(filterInvocation) && this.observeOncePerRequest) {
            filterInvocation.getChain().doFilter(filterInvocation.getRequest(), filterInvocation.getResponse());
        } else {
            if (filterInvocation.getRequest() != null && this.observeOncePerRequest) {
                filterInvocation.getRequest().setAttribute("__spring_security_filterSecurityInterceptor_filterApplied", Boolean.TRUE);
            }

            InterceptorStatusToken token = super.beforeInvocation(filterInvocation);

            try {
                filterInvocation.getChain().doFilter(filterInvocation.getRequest(), filterInvocation.getResponse());
            } finally {
                super.finallyInvocation(token);
            }

            super.afterInvocation(token, (Object)null);
        }
    }

    private boolean isApplied(FilterInvocation filterInvocation) {
        return filterInvocation.getRequest() != null && filterInvocation.getRequest().getAttribute("__spring_security_filterSecurityInterceptor_filterApplied") != null;
    }

    public boolean isObserveOncePerRequest() {
        return this.observeOncePerRequest;
    }

    public void setObserveOncePerRequest(boolean observeOncePerRequest) {
        this.observeOncePerRequest = observeOncePerRequest;
    }
}

???????????

??????????????????????????

????????????????????????????????????????

认证管理器

????????????

AccessDecisionManager

public interface AccessDecisionManager {
    void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException;

    boolean supports(ConfigAttribute attribute);

    boolean supports(Class<?> clazz);
}

?????????????

AbstractAccessDecisionManager

public abstract class AbstractAccessDecisionManager implements AccessDecisionManager, InitializingBean, MessageSourceAware {
    protected final Log logger = LogFactory.getLog(this.getClass());
    private List<AccessDecisionVoter<?>> decisionVoters;
    protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
    private boolean allowIfAllAbstainDecisions = false;


    public boolean supports(ConfigAttribute attribute) {
        Iterator var2 = this.decisionVoters.iterator();

        AccessDecisionVoter voter;
        do {
            if (!var2.hasNext()) {
                return false;
            }

            voter = (AccessDecisionVoter)var2.next();
        } while(!voter.supports(attribute));

        return true;
    }

    public boolean supports(Class<?> clazz) {
        Iterator var2 = this.decisionVoters.iterator();

        AccessDecisionVoter voter;
        do {
            if (!var2.hasNext()) {
                return true;
            }

            voter = (AccessDecisionVoter)var2.next();
        } while(voter.supports(clazz));

        return false;
    }


    public void setMessageSource(MessageSource messageSource) {
    public void setAllowIfAllAbstainDecisions(boolean allowIfAllAbstainDecisions) {

    public List<AccessDecisionVoter<?>> getDecisionVoters() {
    public boolean isAllowIfAllAbstainDecisions() {

    public String toString() {
    public void afterPropertiesSet() {

    protected final void checkAllowIfAllAbstainDecisions() {
    protected AbstractAccessDecisionManager(List<AccessDecisionVoter<?>> decisionVoters) {

?????????????

? ? ? ? ? ? ? ??

AffirmativedBased

public class AffirmativeBased extends AbstractAccessDecisionManager {
    public AffirmativeBased(List<AccessDecisionVoter<?>> decisionVoters) {
        super(decisionVoters);
    }

    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException {
        int deny = 0;
        Iterator var5 = this.getDecisionVoters().iterator();

        while(var5.hasNext()) {
            AccessDecisionVoter voter = (AccessDecisionVoter)var5.next();
            int result = voter.vote(authentication, object, configAttributes);
            switch(result) {
            case -1:
                ++deny;
                break;
            case 1:
                return;
            }
        }

        if (deny > 0) {
            throw new AccessDeniedException(this.messages.getMessage("AbstractAccessDecisionManager.accessDenied", "Access is denied"));
        } else {
            this.checkAllowIfAllAbstainDecisions();
        }
    }
}

?????????????

AccessDecisionVoter

public interface AccessDecisionVoter<S> {
    int ACCESS_GRANTED = 1;
    int ACCESS_ABSTAIN = 0;
    int ACCESS_DENIED = -1;

    boolean supports(ConfigAttribute attribute);

    boolean supports(Class<?> clazz);

    int vote(Authentication authentication, S object, Collection<ConfigAttribute> attributes);
}

?????????????

??????????

?RoleVoter:根据权限判断是否让请求通过

public class RoleVoter implements AccessDecisionVoter<Object> {
    private String rolePrefix = "ROLE_";

    public RoleVoter() {
    }

    public String getRolePrefix() {
        return this.rolePrefix;
    }

    public void setRolePrefix(String rolePrefix) {
        this.rolePrefix = rolePrefix;
    }

    public boolean supports(ConfigAttribute attribute) {
        return attribute.getAttribute() != null && attribute.getAttribute().startsWith(this.getRolePrefix());
    }

    public boolean supports(Class<?> clazz) {
        return true;
    }

    public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) {
        if (authentication == null) {
            return -1;
        } else {
            int result = 0;
            Collection<? extends GrantedAuthority> authorities = this.extractAuthorities(authentication);
            Iterator var6 = attributes.iterator();

            while(true) {
                ConfigAttribute attribute;
                do {
                    if (!var6.hasNext()) {
                        return result;
                    }

                    attribute = (ConfigAttribute)var6.next();
                } while(!this.supports(attribute));

                result = -1;
                Iterator var8 = authorities.iterator();

                while(var8.hasNext()) {
                    GrantedAuthority authority = (GrantedAuthority)var8.next();
                    if (attribute.getAttribute().equals(authority.getAuthority())) {
                        return 1;
                    }
                }
            }
        }
    }

    Collection<? extends GrantedAuthority> extractAuthorities(Authentication authentication) {
        return authentication.getAuthorities();
    }
}

?????????

?????????????

????????????????????????????????????????

使用示例

????????????

????????????????????????????

?????????

AuthorityDto

@Data
public class AuthorityDto {

    private String path;
    private List<String> authorities;
}

??????????

SecurityDataSourceUtil

public class SecurityDataSourceUtil {

    public static Map<String, Collection<ConfigAttribute>> requestAuthoritiesMap = new HashMap<>();

    public static void setAuthorities(String path, Collection<ConfigAttribute> configAttributes){
        requestAuthoritiesMap.put(path, configAttributes);
    }

    public static Collection<ConfigAttribute> getAuthorities(String path){
        return requestAuthoritiesMap.get(path);
    }
}

???????????

CustomFilterSecurityMetadataSource

@Component
public class CustomFilterSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

    @Override
    public boolean supports(Class<?> clazz) {
        return FilterInvocation.class.isAssignableFrom(clazz);
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        Set<ConfigAttribute> configAttributes = new HashSet<>();
        for (Collection<ConfigAttribute> item : SecurityDataSourceUtil.requestAuthoritiesMap.values()){
            configAttributes.addAll(item);
        }

        return configAttributes;
    }

    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        HttpServletRequest request = ((FilterInvocation)object).getRequest();

        for (Map.Entry<String, Collection<ConfigAttribute>> entry: SecurityDataSourceUtil.requestAuthoritiesMap.entrySet()){
            if (new AntPathRequestMatcher(entry.getKey()).matches(request)) {
                return entry.getValue();
            }
        }

        return null;
    }
}

?????????

CustomUrlInterceptor

@Data
@Component
@EqualsAndHashCode(callSuper = true)
public class CustomUrlInterceptor extends AbstractSecurityInterceptor implements Filter, InitializingBean {

    private static final String FILTER_APPLIED = "__spring_security_custom_filterSecurityInterceptor_filterApplied";
    private boolean observeOncePerRequest = true;

    @Resource
    private FilterInvocationSecurityMetadataSource securityMetadataSource;


    public CustomUrlInterceptor() {
    }

    @Override
    public void afterPropertiesSet() {
        List<AccessDecisionVoter<?>> accessDecisionVoters = new ArrayList<>();
        accessDecisionVoters.add(new RoleVoter());

        AccessDecisionManager accessDecisionManager = new AffirmativeBased(accessDecisionVoters);
        this.setAccessDecisionManager(accessDecisionManager);
    }

    public void init(FilterConfig arg0) {
    }

    public void destroy() {
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        this.invoke(new FilterInvocation(request, response, chain));
    }

    public SecurityMetadataSource obtainSecurityMetadataSource() {
        return this.securityMetadataSource;
    }

    public Class<?> getSecureObjectClass() {
        return FilterInvocation.class;
    }

    public void invoke(FilterInvocation filterInvocation) throws IOException, ServletException {
        if (this.isApplied(filterInvocation) && this.observeOncePerRequest) {
            filterInvocation.getChain().doFilter(filterInvocation.getRequest(), filterInvocation.getResponse());
        } else {
            if (filterInvocation.getRequest() != null && this.observeOncePerRequest) {
                filterInvocation.getRequest().setAttribute(FILTER_APPLIED, Boolean.TRUE);
            }

            InterceptorStatusToken token = super.beforeInvocation(filterInvocation);

            try {
                filterInvocation.getChain().doFilter(filterInvocation.getRequest(), filterInvocation.getResponse());
            } finally {
                super.finallyInvocation(token);
            }

            super.afterInvocation(token, null);
        }
    }

    private boolean isApplied(FilterInvocation filterInvocation) {
        return filterInvocation.getRequest() != null && filterInvocation.getRequest().getAttribute(FILTER_APPLIED) != null;
    }

    public boolean isObserveOncePerRequest() {
        return this.observeOncePerRequest;
    }

    public void setObserveOncePerRequest(boolean observeOncePerRequest) {
        this.observeOncePerRequest = observeOncePerRequest;
    }
}

?????????????

WebSecurity

@Configuration
public class WebSecurity {

    @Bean
    public PasswordEncoder initPasswordEncoder(){
        return new Pbkdf2PasswordEncoder();
    }
}

???????????

WebSecurityConfig

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

    @Resource
    private PasswordEncoder passwordEncoder;

    @Resource
    private CustomUrlInterceptor customUrlInterceptor;

    @Bean
    public SecurityFilterChain initSecurityFilterChain(HttpSecurity http) throws Exception{
        http.addFilterAfter(customUrlInterceptor, FilterSecurityInterceptor.class);
        http.csrf().disable();

        return http.formLogin().and().authorizeRequests()
                .antMatchers("/authority").permitAll()
                .antMatchers("/hello").hasRole("admin")
                .anyRequest().authenticated()
                .and().build();
    }

    @Bean
    public UserDetailsService initUserDetailsService(){
        UserDetails userDetails = User.withUsername("gtlx").password(passwordEncoder.encode("123456")).roles("admin").build();

        return new InMemoryUserDetailsManager(userDetails);
    }
}

???????????

HelloController

@RestController
public class HelloController {

    @RequestMapping("/hello")
    public String hello(){
        return "hello";
    }

    @RequestMapping("/hello2")
    public String hello2(){
        return "hello2";
    }
}

????????????

AuthorityController

@RestController
public class AuthorityController {

    @RequestMapping("/authority")
    public String authority(@RequestBody AuthorityDto authorityDto){
        List<ConfigAttribute> configAttributes = new ArrayList<>();
        for (String s: authorityDto.getAuthorities()){
            SecurityConfig securityConfig = new SecurityConfig("ROLE_"+s);
            configAttributes.add(securityConfig);
        }
        SecurityDataSourceUtil.setAuthorities(authorityDto.getPath(), configAttributes);

        return "success";
    }
}

??????????

??????????????????

????????????????????????????????????????

使用测试

????????????

localhost:8080/hello,输入密码

????????????

????????????

????????????

localhost:8080/hello2

????????????

????????????

localhost:8080/authority,路径/hello2添加权限认证

????????????

????????????

localhost:8080/hello2,当前用户没有user权限,禁止访问

????????????

? ? ? ? ? ??

localhost:8080/authority,修改路径权限为admin

????????????

????????????

localhost:8080/hello2,当前用户有admin权限,可正常访问

????????????

?????????????????

??????????????????????????????

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-09-21 00:12:55  更:2022-09-21 00:13:19 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 13:31:11-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码