Spring Boot . 4 -- 定制 Spring Boot 配置
- 覆写 Auto-Configuration 的类
- 利用外部属性进行动态配置 【本文】
- 定制 Error 页面 【第二篇】
Spring Boot的自动配置可以节省很多无趣的配置工作,但是并不是所有的自动配置都能满足需求。比如链接数据库的时候,需要使用一些OR-Mapping 的中间件;比如安全相关的配置需要针对不用的场景/应用/业务进行定制化的开发和配置;或者需要根据不同的运行时条件,做不同的分支决策;等等。所以Sping Boot 提供了两种基本方式,允许开发者对现有的自佛那个配置进行定制化的更改:配置覆写、细粒度的外部属性配置。【explicit configuration overrides、fine-grained configuration with properties】
覆写(Override)Spring Boot 的自动配置
覆写配置可以采用Spring支持的任意一种配置方式:XML、Groovy 脚本、Java 代码 等。这里使用Java代码方式的配置。WebSecurityConfigurerAdapter 提供了覆写SecurityConfig 的入口。做这样的假定:(1)只在登录页面做登录校验,其他页面不进行校验;(2)登陆账户和密码是 user-password;(3)登录这的角色为 USER。
首先定义一个Controller响应Http请求。响应登录、查看登录状态、登出 等Http请求。
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class HelloController { @Autowired private ReaderRepository readerRepository; @RequestMapping(value = "/addUser") public String addUser() { // 向数据库中加入一个User Reader reader = new Reader(); reader.setFullname("pa"); reader.setPassword("password"); reader.setUsername("user"); readerRepository.save(reader); return "index"; } @RequestMapping("/") public String index() { readerRepository.saveAndFlush(new Reader("user","password","password")); return "index"; } @RequestMapping("/hello") public String hello() { return "hello"; } @RequestMapping("/login") public String login() { return "login"; } }
实现自主配置的 安全校验是通过 继承和覆写 WebSecurityConfiguerAdapter 类来实现的,指定需要进行安全校验的类,指定进行校验的数据等,代码如下:
package readinglist; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; @Configuration @EnableWebSecurity // 这个注解启用了定制的安全配置 安全的校验机制按照被注解类的逻辑进行 public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private ReaderRepository readerRepository; @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/").permitAll() // "/" 这个路径下不进行安全校验 .anyRequest().authenticated() // 其他的路径均需要校验 .and() .formLogin() .loginPage("/login") // 默认的登录页面 .permitAll() .and() .logout() .permitAll(); }
// 在这里进行登录校验,通过数据库来进行 用户名和密码的 校验 @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth .userDetailsService(new UserDetailsService() { @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { return readerRepository.findOne(username); } }); } public void setReaderRepository(ReaderRepository readerRepository) { this.readerRepository = readerRepository; } }
以上就是最核心的代码。其他的自主配置的方式基本一致。
辅助的代码:Reader 的定义。
package readinglist; import java.util.Arrays; import java.util.Collection; import javax.persistence.Entity; import javax.persistence.Id; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; @Entity public class Reader implements UserDetails { private static final long serialVersionUID = 1L; @Id public String username; public String fullname; public String password; @Override public Collection<? extends GrantedAuthority> getAuthorities() { return Arrays.asList(new SimpleGrantedAuthority("USER")); } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getFullname() { return fullname; } public void setFullname(String fullname) { this.fullname = fullname; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
Repository 的代码:
package readinglist; import org.springframework.data.jpa.repository.JpaRepository; public interface ReaderRepository extends JpaRepository<Reader, String> { }