SpringSecurity生成权限流程源码分析

SpringSecurity生成权限流程源码分析

  1. 自定义match路径,

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/lib/*", "/js/*").permitAll()
                //配置POST访问/users需要有ADMIN权限
                .mvcMatchers(HttpMethod.POST, "/users").hasRole("ADMIN")
                //允许跨域的所有请求
                .mvcMatchers(HttpMethod.OPTIONS).permitAll()
                //配置GET访问/users所有用户都可以
                .mvcMatchers(HttpMethod.GET,  "/users").hasAnyRole("ADMIN", "USER")
                //配置所有请求都需要授权
                .anyRequest().authenticated()
    
  2. match调用authorizeRequests()创建自定义的ExpressionUrlAuthorizationConfigurer

    我们直接从ExpressionUrlAuthorizationConfigurer类开始

    它通过获取默认的GrantedAuthorityDefaults.class来定义前缀,但是此类默认不会创建

    所以我们可以通过创建Bean: GrantedAuthorityDefaults.class来自定义前缀

    ExpressionUrlAuthorizationConfigurer在没有 GrantedAuthorityDefaults.class的情况下前缀默认为ROLE_

    GrantedAuthorityDefaults类

    public final class GrantedAuthorityDefaults {
       private final String rolePrefix;
       public GrantedAuthorityDefaults(String rolePrefix) {
          this.rolePrefix = rolePrefix;
       }
       public String getRolePrefix() {return this.rolePrefix; }
    }
    

    ExpressionUrlAuthorizationConfigurer类

    public ExpressionUrlAuthorizationConfigurer(ApplicationContext context) {
       String[] grantedAuthorityDefaultsBeanNames = context.getBeanNamesForType(GrantedAuthorityDefaults.class);
       if (grantedAuthorityDefaultsBeanNames.length == 1) {
          GrantedAuthorityDefaults grantedAuthorityDefaults = context.getBean(grantedAuthorityDefaultsBeanNames[0],
                GrantedAuthorityDefaults.class);
          this.rolePrefix = grantedAuthorityDefaults.getRolePrefix();
       }
       else {
          this.rolePrefix = "ROLE_";
       }
       this.REGISTRY = new ExpressionInterceptUrlRegistry(context);
    }
    
  3. 配置match路径时会调用ExpressionUrlAuthorizationConfigurerantMatcher()方法,该方法通过RequestMatchers.antMatchers(antPatterns)将传入的antPatterns封装成List,最后再把unmappedMatchers 属性设置为该List和返回一个List封装的AuthorizedUrl

  4. AbstractRequestMatcherRegister

    public C antMatchers(String... antPatterns) {
       return chainRequestMatchers(RequestMatchers.antMatchers(antPatterns));
    }
    protected final C chainRequestMatchers(List<RequestMatcher> requestMatchers) {
        this.unmappedMatchers = requestMatchers;
        return chainRequestMatchersInternal(requestMatchers);
    }
    protected AuthorizedUrl chainRequestMatchersInternal(List<RequestMatcher> requestMatchers) {
        return new AuthorizedUrl(requestMatchers);
    }
    

    RequestMatchers

    static List<RequestMatcher> antMatchers(HttpMethod httpMethod, String... antPatterns) {
       String method = (httpMethod != null) ? httpMethod.toString() : null;
       List<RequestMatcher> matchers = new ArrayList<>();
       for (String pattern : antPatterns) {
          matchers.add(new AntPathRequestMatcher(pattern, method));
       }
       return matchers;
    }
    
  5. 配置match时还会调用ExpressionUrlAuthorizationConfigurermvcMatchers(method, patterns)方法,该方法调用createMvcMatchersmethod,patterns封装在一个List<MvcRequestMatcher>中,继而返回一个封装了List<MvcRequestMatcher>MvcMatchersAuthorizedUrl

    ExpressionUrlAuthorizationConfigurer

    @Override
    public MvcMatchersAuthorizedUrl mvcMatchers(HttpMethod method, String... mvcPatterns) {
        return new MvcMatchersAuthorizedUrl(createMvcMatchers(method, mvcPatterns));
    }
    protected final List<MvcRequestMatcher> createMvcMatchers(HttpMethod method, String... mvcPatterns) {
        HandlerMappingIntrospector introspector = this.context.getBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME,
                                                                       HandlerMappingIntrospector.class);
        List<MvcRequestMatcher> matchers = new ArrayList<>(mvcPatterns.length);
        for (String mvcPattern : mvcPatterns) {
            MvcRequestMatcher matcher = new MvcRequestMatcher(introspector, mvcPattern);
            opp.postProcess(matcher);
            if (method != null) {
                matcher.setMethod(method);
            }
            matchers.add(matcher);
        }
        return matchers;
    }
    
  6. 返回的Matchers通过调用permitAll、hasRole、hasAnyRole等方法(全部设置权限的方法可以在AuthorizedUrl中找到)设置权限

    我们只分析一个hasRole的源码,如下:

    ExpressionUrlAuthorizationConfigurers

    public ExpressionInterceptUrlRegistry hasRole(String role) {
       return access(ExpressionUrlAuthorizationConfigurer
             .hasRole(ExpressionUrlAuthorizationConfigurer.this.rolePrefix, role));
    }
    //hasRole将前缀和传入的role拼接在一起
    private static String hasRole(String rolePrefix, String role) {
        return "hasRole('" + rolePrefix + role + "')";
    }
    //该方法调用interceptUrl(具体看下面),并返回REGISTRY
    public ExpressionInterceptUrlRegistry access(String attribute) {
        interceptUrl(this.requestMatchers, SecurityConfig.createList(attribute));
        return ExpressionUrlAuthorizationConfigurer.this.REGISTRY;
    }
    //该方法会将所有requestMatchers封装在UrlMapping中并传入REGISTRY
    private void interceptUrl(Iterable<? extends RequestMatcher> requestMatchers,
                              Collection<ConfigAttribute> configAttributes) {
        for (RequestMatcher requestMatcher : requestMatchers) {
            this.REGISTRY.addMapping(
                new AbstractConfigAttributeRequestMatcherRegistry.UrlMapping(requestMatcher, configAttributes));
        }
    }
    

生成权限流程到这里就结束了,至于权限是如何认证的,那就是FilterSecurityIntercepter的事情了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值