Skip to content
X_Smart edited this page Jun 3, 2018 · 6 revisions

Java配置

  • Spring Security从3.2开始支持通过Java代码配置,不需要使用任何xml。

5.1Web应用安全的Java配置

  1. 创建过滤器 创建一个配置类

     @EnableWebSecurity  // 创建一个名为springSecurityFilterChain 的Filter
       public class SecurityConfig extends WebSecurityConfigurerAdapter{
       @Autowired
       public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
       	auth
       		.inMemoryAuthentication()
       			.withUser("user").password("password").roles("USER");
       }
    
    }
  2. 注册过滤器 实例化自己创建的配置类。

5.2 HttpSecurity

  • SpringSecurity 提供的默认配置

    protected void configure(HttpSecurity http) throws Exception {
    
    	http.csrf().disable(); //关闭csrf
    
    	http
    
    	// #4 不验证该请求 http请求的方式,跳过所有的静态资源 css js
    
    	.authorizeRequests().antMatchers("/signup", "/about").permitAll()
    
    			.antMatchers("/admin/").hasRole("ADMIN") // #6 给相关角色相关的访问权限
    
    			.anyRequest().authenticated() // #7 其余所有的url都需要登录
    
    			.and().formLogin() // #8 默认使用form提交的方式
    
    			.loginPage("/login") // #9  重写登录页面,不需要权限
    
    			.permitAll(); // #5
    
    }
  • Java配置中的and()方法类似于xml配置中的结束标签。

5.3 Java Configuration and Form Login

  • 系统会自己提供login页面
  • 重写login页面 提交的action必须是login ,自己重写login 的GET提交方式,POST的方式为系统自己提供。

5.4 Authorize Requests

  1. http.authorizeRequests()方法有很多子方法,每个子匹配器将会按照声明的顺序起作用。
  2. 指定用户可以访问的多个url模式。特别的,任何用户可以访问以"/resources"开头的url资源,或者等于"/signup"或about
  3. 任何以"/admin"开头的请求限制用户具有 "ROLE_ADMIN"角色。你可能已经注意的,尽管我们调用的hasRole方法,但是不用传入"ROLE_"前缀
  4. 任何以"/db"开头的请求同时要求用户具有"ROLE_ADMIN"和"ROLE_DBA"角色。
  5. 任何没有匹配上的其他的url请求,只需要用户被验证。

5.5 Handling Logouts

  • 默认情况下访问/logout将会将用户注销,包含的内容有:

    protected void configure(HttpSecurity http) throws Exception {
    
    http
    
    	.logout() //1、提供注销支持,当使用 WebSecurityConfigurerAdapter时这将会被自动应用
    
    		.logoutUrl("/my/logout") //触发注销的 URL (默认为/logout)。如果启用了 CSRF 保护 (默认), 则请求也必须是 POST。
    
    		.logoutSuccessUrl("/my/index")  //注销操作发生后重定向到的url,默认为 /login?logout。
    
        //让我们指定一个自定义LogoutSuccessHandler。如果指定了此项, 则忽略logoutSuccessUrl()
    
        .logoutSuccessHandler(logoutSuccessHandler)
    
    		.invalidateHttpSession(true) //指定在注销的时候是否销毁 HttpSession 。默认为True
    
        //添加一个 LogoutHandler。默认情况下, SecurityContextLogoutHandler 被作为最后一个 LogoutHandler 。
    
        .addLogoutHandler(logoutHandler)
    
        //允许指定在注销成功时删除的 cookie 名称。这是显式添加CookieClearingLogoutHandler的快捷方式
    
        .deleteCookies(cookieNamesToClear)       
    
    		.and()
    
    	...
    
    }
  • LogoutHandler 不会抛出异常

  • LogoutSuccessHandler 会抛出异常

5.6 Authentication

  1. 基于内存的验证

    public void configureGlobal(AuthenticationManagerBuilder auth)
    
       throws Exception {
    
      auth
    
      .inMemoryAuthentication()
    
      .withUser("username").password("password")
    
        .roles("USER").
    
      and().withUser("root").password("root")
    
        .roles("ROOT");
    
     }
  2. JDBC验证

    @Autowired
    
    private DataSource dataSource;
    
    @Autowired
    
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    
    	auth
    
    		.jdbcAuthentication()
    
    			.dataSource(dataSource)
    
    			.withDefaultSchema()
    
    			.withUser("user").password("password").roles("USER").and()
    
    			.withUser("admin").password("password").roles("USER", "ADMIN");
    
    }
  3. LDAP验证

    @Autowired
    
    private DataSource dataSource;
    
    @Autowired
    
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    
    	auth
    
    		.ldapAuthentication()
    
    			.userDnPatterns("uid={0},ou=people")
    
    			.groupSearchBase("ou=groups");
    
    }

    需要添加 用户.Ldif

    dn: ou=groups,dc=springframework,dc=org
    
    objectclass: top
    
    objectclass: organizationalUnit
    
    ou: groups
    
    
  4. UserDetailsService

  • 通过将自定义UserDetailsService公开为 bean, 可以定义自定义身份验证。 注:只有在未填充AuthenticationManagerBuilder且未定义AuthenticationProviderBean时才使用此方法。
  • 可以配置PasswordEncoder ,来指定密码的编码方式
  • 无论基于怎样的验证方式都要注入AuthenticationManagerBuilder对象

5.7 Multiple HttpSecurity

  1. 按照正常的方式配置验证
  2. 创建包含@Order的WebSecurityConfigurerAdapter的实例, 以指定应首先考虑哪个WebSecurityConfigurerAdapter 。
  3. http.antMatcher声明此HttpSecurity仅适用于以/api/开头的 url。
  4. 创建另一个 WebSecurityConfigurerAdapter实例。如果URL没有以 /api/开头,这个配置将会被使用。这个配置在 ApiWebSecurityConfigurationAdapter 之后生效,因为其含有一个 @Order值为1.没有 @Order默认是最后一个生效。

5.8 Method Security

  1. 通过在配置类上添加注解@EnableGlobalMethodSecurity开启基于注解的安全验证,然后可以在类或方法上添加@Secured注解会相应地限制对该方法的访问

    public interface BankService {
    
    @Secured("IS_AUTHENTICATED_ANONYMOUSLY")
    
    public Account readAccount(Long id);
    
    @Secured("IS_AUTHENTICATED_ANONYMOUSLY")
    
    public Account[] findAccounts();
    
    @Secured("ROLE_TELLER")
    
    public Account post(Account account, double amount);
    
    }

可以用java代码进行替代:

public interface BankService {

@PreAuthorize("isAnonymous()")

public Account readAccount(Long id);

@PreAuthorize("isAnonymous()")

public Account[] findAccounts();

@PreAuthorize("hasAuthority('ROLE_TELLER')")

public Account post(Account account, double amount);

}
  1. 需要执行比@EnableGlobalMethodSecurity批注允许的更复杂的操作。对于这些实例, 可以扩展GlobalMethodSecurityConfiguration , 以确保子类上存在@EnableGlobalMethodSecurity批注。

5.9 Post Processing Configured Objects

  • 为了更加灵活的满足开发人员更高级的配置需求,SpringSecurity引入了 ObjectPostProcessor 的概念,其可以用来修改或者替代通过Java方式配置创建的对象实例。

    .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
    
                                 public <O extends FilterSecurityInterceptor> O postProcess(
    
                                                 O fsi) {
    
                                         fsi.setPublishAuthorizationSuccess(true);
    
                                         return fsi;
    
                                 }

5.10 Custom DSLs

Spring Security支持开发人员自定义拦截方式。

  1. 创建自定义的拦截规则:

    public class MyCustomDsl extends AbstractHttpConfigurer<CorsConfigurerMyCustomDsl, HttpSecurity> {
    
    private boolean flag;
    
    ...
    
    }
  2. 通过http.apply(customDsl()).flag(true)进行引用。

  3. 执行顺序 调用配置的配置方法中的代码 调用 MyCustomDsl 的 init 方法中的代码 调用 MyCustomDsl 的配置方法中的代码

  4. 显示执行 .apply(customDsl()).disable()