转载

34.SpringSecurity-SpringSecurity Oauth权限表达式

前言

34.SpringSecurity-SpringSecurity Oauth权限表达式

  1. 之前我们看了Spring Security在控制授权这一块他的核心代码,我们看到最后请求通过或者不通过都是转成了权限的表达式,然后交给了一个WebExpressionVoter去评估你的表达式。这个表达式评估的结果是true,那么访问就通过,如果评估的结果是false,那么访问就不通过。那么问题来了,SpringSecurity有多少种权限表达式?每一种权限表达式的写法是怎样的?代表的意思是什么?

内容

1. 表达式说明

34.SpringSecurity-SpringSecurity Oauth权限表达式

上面的表达式都是在WebSecurityConfig可以配置的: 每一个表达式都是对应了HttpSecurity的一个方法,并且是跟在antMatchers之后的。

34.SpringSecurity-SpringSecurity Oauth权限表达式

比如:antMatchers("xxx").permitAll();

antMatchers---指定url

表达式---指定授权

如果需要多个表达式合并统一起来,需要自己通过.access来自己定义: 34.SpringSecurity-SpringSecurity Oauth权限表达式

另一个需求是我们能不能通过.access自定义逻辑:让系统读取我们自己的逻辑而不是使用系统的默认逻辑。

2. 剥离用户自己模块的url服务

2.1 抽离思想

目前我们的安全配置是写在我们的安全模块代码spring-security-core里面的,不管是spring-security-web和spring-security-app.都有一些针对url的安全配置。但是问题是这些url有些是我们的安全模块提供的 ,比如说一下url:

34.SpringSecurity-SpringSecurity Oauth权限表达式

都是安全模块提供的。

但是用户注册("/user/register"),和获取用户的url("/user/*"),他其实是我们的spring-security-demo项目提供的。也就是使用我们安全模块的人提供的安全服务。对于安全模块来说,事先我们并不知道谁会使用我们的安全模块。我也不知道使用此安全模块的url服务。所以针对于使用安全模块的url服务我们应该剥离出去。

34.SpringSecurity-SpringSecurity Oauth权限表达式

实现思路很简单,我们提供一个接口,在我们自己的权限模块里面去实现这个接口(把和安全模块相关的配置写到这个接口里面)。如果是用户模块的话,用户模块自己去实现此接口(将用户模块的url写到用户模块中) 如果我们应用A都需要多有的url服务,那么我们就让应用A去依赖这两个模块。应用A也有这个AuthorizeConfigProvider的实现。所以在应用A的spring容器中 一共有3个模块的权限配置提供者的实现:他们是权限模块、用户模块、应用A实现模块。

1.权限模块:权限模块自身的url权限配置

2.用户模块:用户模块的url权限配置

3.应用A实现模块:应用A特有的url权限配置

最后,在我们的权限模块core中只需要提供一个:AuthorizeConfigManager类,这个类的作用是:把Spring容器里面所有AuthorizeConfigProvider接口的实现全部收集起来。然后按照各个实现的配置给配置好。

假如我们现在有一个应用B,应用B也有自己的AuthorizeConfigProvider的实现并且依赖了权限模块实现、用户模块实现,此时AuthorizeConfigManager类也会收集起三个模块:权限模块、用户模块、应用A实现模块。最终应用A和应用B权限是不同的,但是我们的权限模块core是不管的。

2.2 抽离-代码实现

2.2.1 spring-security-core创建AuthorizeConfigProvider

  1. 我们创建包:com.yxm.security.core.authorize,然后在此包下创建接口:AuthorizeConfigProvider
  2. 我们从spring-security-web的WebSecurityConfig的配置里面获取授权url开始的权限对象:
    34.SpringSecurity-SpringSecurity Oauth权限表达式
  3. authorizeRequests()返回的对象是:
    34.SpringSecurity-SpringSecurity Oauth权限表达式
  4. 我们将其封装到授权配置provider中去:

    public interface AuthorizeConfigProvider {
     void  configure(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry config);
    }

2.2.2 core实现AuthorizeConfigProvider

MyAuthorizeConfigProvider实现AuthorizeConfigProvider 接口,并申明为Spring的组件。

@Component
public class MyAuthorizeConfigProvider implements AuthorizeConfigProvider {

    @Autowired
    private SecurityProperties securityProperties;

    @Override
    public void configure(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry config) {
        config.antMatchers(SecurityConstants.DEFAULT_UNAUTHENTICATION_URL,
                   SecurityConstants.DEFAULT_LOGIN_PROCESSING_URL_MOBILE,
                   securityProperties.getBrowser().getLoginPage(),
                   SecurityConstants.DEFAULT_VALIDATE_CODE_URL_PREFIX+"/*",
                   securityProperties.getBrowser().getSignUpUrl())
                .permitAll();
    }
}

2.2.3 core中定义AuthorizeConfigManager

public interface AuthorizeConfigManager {
    void  configure(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry config);
}

2.2.4 core中定义AuthorizeConfigManager的实现:MyAuthorizeConfigManager

@Component
public class MyAuthorizeConfigManager implements AuthorizeConfigManager {
    /**
     * 作用:把系统的provider全部收集起来
     * @param config
     */
    @Autowired
    private Set<AuthorizeConfigProvider> authorizeConfigProviders;

    @Override
    public void configure(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry config) {
         for (AuthorizeConfigProvider authorizeConfigProvider:authorizeConfigProviders){
             authorizeConfigProvider.configure(config);
         }

         //除了上面配置的所有权限外,其他请求都需要授权
        config.anyRequest().authenticated();
    }
}

2.2.5 web里面改造

@Configuration
public class WebSecurityConfig extends AbstractChannelSecurityConfig {

    @Autowired
    private ValidateCodeSecurityConfig validateCodeSecurityConfig;//验证码过滤器配置

    @Autowired
    private SmsCodeAuthenticationSecurityConfig smsCodeAuthenticationSecurityConfig; //短信验证码授权配置

    @Autowired
    private SpringSocialConfigurer mySocialSecurityConfig;

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private SecurityProperties securityProperties;

    @Autowired
    private DataSource dataSource;

    @Autowired
    private AuthorizeConfigManager authorizeConfigManager;

    @Bean
    public PersistentTokenRepository persistentTokenRepository(){
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        //
        //因为是Jdbc操作,所以我们需要注入数据源:org.springframework.jdbc.core.support.JdbcDaoSupport
        //tokenRepository继承org.springframework.jdbc.core.support.JdbcDaoSupport
        tokenRepository.setDataSource(dataSource);
        System.out.println("PersistentTokenRepository--dataSource:>dataSource");
        //tokenRepository.setCreateTableOnStartup(true);//系统启动的时候创建:CREATE_TABLE_SQL表
        return tokenRepository;

    }
    /**
     * 定义web安全配置类:覆盖config方法
     * 1.参数为HttpSecurity
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        applyPasswordAuthenticationConfig(http);

         http.apply(validateCodeSecurityConfig)
                .and()
             .apply(smsCodeAuthenticationSecurityConfig)
                .and()
             .apply(mySocialSecurityConfig)//配置第三方social
                 .and()
             .rememberMe()
                .tokenRepository(persistentTokenRepository())
                .tokenValiditySeconds(securityProperties.getBrowser().getRememberMeSeconds())//配置token失效秒数
                .userDetailsService(userDetailsService)
                .and()
                 .csrf().disable();

        authorizeConfigManager.configure(http.authorizeRequests());
   }
}

2.2.6 spring-security-app里面改造

@Configuration
@EnableResourceServer
public class MyResourceServerConfig extends ResourceServerConfigurerAdapter {
    @Autowired
    private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;
    @Autowired
    private MyAuthenticationFailureHandler myAuthenticationFailureHandler;
    @Autowired
    private SmsCodeAuthenticationSecurityConfig smsCodeAuthenticationSecurityConfig; //短信验证码授权配置
    @Autowired
    private SpringSocialConfigurer mySocialSecurityConfig;
    @Autowired
    private SecurityProperties securityProperties;
    @Autowired
    private ValidateCodeSecurityConfig validateCodeSecurityConfig;//验证码过滤器配置

    @Autowired
    private OpenIdAuthenticationSecurityConfig openIdAuthenticationSecurityConfig;

    @Autowired
    private AuthorizeConfigManager authorizeConfigManager;


    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.formLogin()
                .loginPage(SecurityConstants.DEFAULT_UNAUTHENTICATION_URL)
                .loginProcessingUrl(SecurityConstants.DEFAULT_LOGIN_PROCESSING_URL_FORM)
                .successHandler(myAuthenticationSuccessHandler)
                .failureHandler(myAuthenticationFailureHandler);

        http.apply(validateCodeSecurityConfig)
                .and()
                .apply(smsCodeAuthenticationSecurityConfig)
                .and()
                .apply(mySocialSecurityConfig)//配置第三方social
                .and()
                .apply(openIdAuthenticationSecurityConfig)
                .and()
                .csrf().disable();

        authorizeConfigManager.configure(http.authorizeRequests());
    }
}

2.2.7 spring-security-demo改成

除了core里面的配置,其他用户注册和用户获取的授权都是demo项目自己的配置。

首先先实现:AuthorizeConfigProvider的类:DemoAuthorizeConfigProvider

@Component
public class DemoAuthorizeConfigProvider implements AuthorizeConfigProvider {
    @Override
    public void configure(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry config) {
         config.antMatchers("/user").hasRole("ADMIN");
    }
}

然后在授权时候返回的用户配置上即可:

34.SpringSecurity-SpringSecurity Oauth权限表达式

3.测试

我们访问登录页面 http://127.0.0.1 :8088/login.html

34.SpringSecurity-SpringSecurity Oauth权限表达式

访问: http://127.0.0.1 :8088/user时候:

34.SpringSecurity-SpringSecurity Oauth权限表达式

原文  https://segmentfault.com/a/1190000022100705
正文到此结束
Loading...