SpringBoot自定义配置

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_41723615/article/details/88343100

覆盖springboot自动配置

围绕应用程序安全有很多决策要做,SpringBoot不能替你做决定。虽然SpringBoot为安全提供了一些基本的自动配置,但是你还需要自己覆盖一些配置以满足特定的安全要求。想知道要如何用显式的配置来覆盖自动配置,我们先从为阅读列表应用程序添加Spring Security入手。在了解自动配置提供了什么之后,我们再来覆盖基础的安全配置,以满足特定的场景需求。

保护应用程序

对于安全工作只需要添加Security起步依赖。以maven为例:

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

Security起步依赖在classpath里添加了Spring Security(和其他一些东西)。classpath里有Spring Security后,自动配置就能介入其中创建一个基本的Spring Security配置。

创建自定义的安全配置

直接显式的写一段配置,这段显式配置的形式不限,xml和groovy都可以。

SecurityConfig安全配置类:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private  ReaderRepository readerRepository;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                     //要求登录者有READER角色
                    .antMatchers("/").access("hasRole('READER')")
                    .antMatchers("/**").permitAll()

                .and()

                .formLogin()
                    //设置登录表单的路劲
                    .loginPage("/login")
                    .failureUrl("/login?error=true");
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                //定义自定义UserDetailsService
                .userDetailsService(new UserDetailsService() {
                    @Override
                    public UserDetails loadUserByUsername(String username)
                            throws UsernameNotFoundException {
                        return readerRepository.findOne(username);
                    }
                });
    }
}

通过这个自定义的安全配置类,我们让spring boot跳过了安全自动配置,转而使用我们的安全配置。

扩展了WebSecurityConfigurerAdapter的配置类可以覆盖两个不同的configure()方法。在SecurityConfig里,第一个configure()方法指明

,“/”(ReadingListController的方法映射到了该路径)的请求只有经过身份认证且拥有READER角色的用户才能访问。其他的所有请求路径向所有用户开放了访问权限。这里还将登录页和登录失败页(带有一个error属性)指定到了/login。
Spring Security为身份认证提供了众多选项,后端可以是JDBC(Java Database Connectivity)、LDAP和内存用户存储。在这个应用程序中,我们会通过JPA用数据库来存储用户信息。第二个configure()方法设置了一个自定义的UserDetailsService,这个服务可以是任意实现了UserDetailsService的类,用于查找指定用户名的用户。

用于持久化读者信息的仓库接口:


public interface ReaderRepository extends JpaRepository<Reader,String> {

}

无需自己实现ReaderRepository。这是因为它扩展了JpaRepository,Spring Data JPA会在运行时自动创建它的实现。这为你提供了18个操作Reader实体的方法。

定义Reader的JPA实体

@Entity
public class Reader implements UserDetails {

    private static final long serialVersionUID = 1L;

    @Id
    private String username;
    private String fullname;
    private String password;

    //setter\getter略

    //授予READER权限
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return Arrays.asList(new SimpleGrantedAuthority("READER"));
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }
    @Override
    public boolean isEnabled() {
        return true;
    }
}

Reader用了@Entity注解,所以这是一个JPA实体。此外,它的username字段上有@Id注解,表明这是实体的ID。

因为username应该能唯一标识一个Reader。

你应该还注意到Reader实现了UserDetails接口以及其中的方法,这样Reader就能代表Spring Security里的用户了。getAuthorities()方法被覆盖过了,始终会为用户授予READER权限。isAccountNonExpired()、isAccountNonLocked()、isCredentialsNonExpired()和isEnabled()方法都返回true,这样读者账户就不会过期,不会被锁定,也不会被撤销。重新构建并重启应用程序后,你应该就能以读者身份登录应用程序了。

保持简单

在一个大型应用程序里,赋予用户的授权本身也可能是实体,它们被维护在独立的数据表里。同样,表示一个账户是否为非过期、非锁定且可用的布尔值也是数据库里的字段。

在安全配置方面,我们还能做更多事情。

再重申一次,想要覆盖Spring Boot的自动配置,你所要做的仅仅是编写一个显式的配置。Spring Boot会发现你的配置,随后降低自动配置的优先级,以你的配置为准。想弄明白这是如何实现的,让我们揭开Spring Boot自动配置的神秘面纱,看看它是如何运作的,以及它是怎么允许自己被覆盖的。

掀开自动配置的神秘面纱

Spring Boot自动配置自带了很多配置类,每一个都能运用在你的应用程序里。它们都使用了Spring 4.0的条件化配置,可以在运行时判断这个配置是该被运用,还是该被忽略。

@ConditionalOnMissingBean注解是覆盖自动配置的关键。Spring Boot的DataSourceAutoConfiguration中定义的JdbcTemplate Bean就是一个非常简单的例子,演示了@ConditionalOnMissingBean如何工作:

@Bean 
@ConditionalOnMissingBean(JdbcOperations.class) 
public JdbcTemplate jdbcTemplate() { 
   return new JdbcTemplate(this.dataSource); 
} 

jdbcTemplate()方法上添加了@Bean注解,在需要时可以配置出一个JdbcTemplateBean。但它上面还加了@ConditionalOnMissingBean注解,要求当前不存在JdbcOperations类型(JdbcTemplate实现了该接口)的Bean时才生效。如果当前已经有一个JdbcOperationsBean了,条件即不满足,不会执行jdbcTemplate()方法。

什么情况下会存在一个JdbcOperations Bean呢?Spring Boot的设计是加载应用级配置,随后再考虑自动配置类。因此,如果你已经配置了一个JdbcTemplate Bean,那么在执行自动配置时就已经存在一个JdbcOperations类型的Bean了,于是忽略自动配置的JdbcTemplate Bean。

关于Spring Security,自动配置会考虑几个配置类。在这里讨论每个配置类的细节是不切实际的,但覆盖Spring Boot自动配置的安全配置时,最重要的一个类是SpringBootWebSecurityConfiguration。以下是其中的一个代码片段:

@Configuration 
@EnableConfigurationProperties 
@ConditionalOnClass({ EnableWebSecurity.class }) 
@ConditionalOnMissingBean(WebSecurityConfiguration.class) 
@ConditionalOnWebApplication 
public class SpringBootWebSecurityConfiguration { 
... 
} 

如你所见,SpringBootWebSecurityConfiguration上加了好几个注解。看到@ConditionalOnClass注解后,你就应该知道Classpath里必须要有@EnableWebSecurity注解。@ConditionalOnWebApplication 说明这必须是个 Web 应用程序。 @ConditionalOnMissingBean注解才是我们的安全配置类代替SpringBootWebSecurityConfiguration的关键所在。

@ConditionalOnMissingBean注解要求当下没有WebSecurityConfiguration类型的Bean。虽然表面上我们并没有这么一个Bean,但通过在SecurityConfig上添加@EnableWebSecurity注解,我们实际上间接创建了一个WebSecurityConfiguration Bean。所以在自动配置时,这个Bean就已经存在了,@ConditionalOnMissingBean条件不成立,SpringBootWebSecurityConfiguration提供的配置就被跳过了。


 

猜你喜欢

转载自blog.csdn.net/qq_41723615/article/details/88343100