文件替换
在SpringBoot中,配置文件被自身的一系列强大的智能属性接管,但是其中的一些自动化配置不是我们想要的,或者距离目标有些许差距.这个时候就需要进行覆盖配置. 在使用Gradle进行项目管理的时候,如果我们在引入
org.springframework.boot:spring-boot-starter-web
它会引入一种处理json的jar包:
我们在项目中可能需要使用低版本的处理工具,或者其他的处理工具. 在Maven中使用标签将其中的
com.fasterxml.fastjson.core
给排除掉. 在Gradle中使用:
{
exclude group:'com.fasterxml.jackson.core'
}
compile("...")
除了替换新的版本,也可以用来对项目进行瘦身或者对进行同类型工具的排除. 一般就是在Gradle或者Maven配置文件中进行排除,然后引入新的版本,按照正常的引入方式.
配置覆盖
使用SpringBoot自带的文件安全模块,结果总是差强人意. 因为你不但要忍受简陋的显示框,更要去日志中寻找密码.希望能自定义安全模块对其进行配置覆盖.
package com.pandy.readinglist.config;
import com.pandy.readinglist.dao.ReaderRepository;
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;
/**
* @author Pandy
* @version 1.0
* @date 10:19
*/
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private ReaderRepository readerRepository;
@Override
protected void configure(HttpSecurity http) throws Exception {
// "/"的请求只有经过身份验证才能且拥有Reader角色的用户才能访问
http.authorizeRequests().antMatchers("/")
.access("hasRole('READER')")//要求登录者有READER角色
.antMatchers("/**").permitAll()//其他的所有访问请求路径对所有的用户开放了权限
.and()
.formLogin()
.loginPage("/login")//设置登录表单的路径
.failureUrl("/login?error=true");//同时将登录页与登录失败页指定到了/login
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(new UserDetailsService() {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return (UserDetails) readerRepository.findById(username).get();
}
});
}
}
通过此配置,SpringBoot跳过了默认的自动配置,转而使用我们的配置. 通过实现WebSecurityConfigurerAdapter接口,覆盖两个方法,第一个方法configure(),"/"的请求只有经过身份验证并且拥有READER角色的用户才能访问.其他的所有请求路径对所有的用户放开了访问权限.这里还将登录页以及登录失败页指定到了/login.
package com.pandy.readinglist.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import java.io.Reader;
/**
* @author Pandy
* @version 1.0
* @date 10:33
*/
public interface ReaderRepository extends JpaRepository<Reader,String> {
}
在这个应用程序中我们会用JPA用数据库来存储用户信息.第二个configure()方法设置了一个自定义的userDetailsService,这个服务是任意实现了userDetailsService的类,用于查找用户名的用户.
package com.pandy.readinglist.bean;
import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import javax.persistence.Entity;
import javax.persistence.Id;
import java.util.Arrays;
import java.util.Collection;
/**
* @author Pandy
* @version 1.0
* @date 10:49
*/
@Data
@Entity
public class Reader implements UserDetails {
@Id
private String username;
private String fullname;
private String password;
/**
* 始终为用户授予READER权限
* @return
*/
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Arrays.asList(new SimpleGrantedAuthority("READER"));
}
/*@Override
public String getPassword() {
return null;
}
@Override
public String getUsername() {
return null;
}*/
/**
* 不过期 不加锁 不禁用
* @return
*/
@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实现了UserDetails接口以及其中的方法,这样Reader就能代表Spring Security里的用户了.getAuthorities()方法被覆盖过了.始终会为用户授予READER权限. 以及包括其中的是否过期,禁用,加锁.我们将其全部设置为true.表示不过期,不禁用,不加锁. 这个使用启动SpringBoot容器就能以读者的身份登录应用程序了.
通过属性文件外置配置
在application.yml中书写的自定义配置能够覆盖一些原有的默认配置,例如
server.port = 8000
将默认的服务器8080端口修改为8000; SpringBoot在启动的时候会检查200多项此类大大小小的配置.
logging:
level:
root: WARN
org:
springframework:
security: DEBUG
path: /var/logs
file: BookWorm.log
spring:
datasource:
url: jdbc:mysql://localhost/readinglist
username: root
password: root
amazon:
associateId: tinyfry520
当应用程序部署在不同的环境中时就需要配置不同的配置.Spring通过Profile注解来设置特定的环境的配置. 当需要在多重环境中进行切换的时候通过Profixe注解可以实现,也可以在配置文件中完成.
logging:
level:
root: WARN
org:
springframework:
security: DEBUG
path: /var/logs
file: BookWorm.log
spring:
datasource:
url: jdbc:mysql://localhost/readinglist
username: root
password: root
amazon:
associateId: tinyfry520
# driver-class-name: com.mysql.jdbc.Driver
# 在一个yml文件中可以配置多个不同环境中的配置文件
---
spring:
profiles: development
logging:
level:
root: DEBUG
---
spring:
profiles: production
logging:
path: /tmp/
file: BookWorm.log
level:
root: WARN
自定义错误页面
SpringBoot自动配置的默认错误处理器会查找名为error的视图,如果找不到就用默认的白标错误视图.
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Oops</title>
<link rel="stylesheet" th:href="@{/style.css}"></link>
</head>
<html>
<div class="errorPage">
<span class="oops">Oops!</span><br/>
<img th:src="@{/MissingPage.jpg}"></img>
<p>There seems to be a problem with the page you requested
(<span th:text="${path}"></span>)</p>
<p th:text="${'Details:' + message}"></p>
</div>
</html>
</html>