一.Spring Security
快速⼊⻔
1.
添加
security
启动器
在项⽬的
pom.xml
⽂件中引⼊
Spring Security
安全框架的依赖启动器
spring-boot-starter-security
。
<!– Spring Security
提供的安全管理依赖启动器
–>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-security
</artifactId>
</dependency>
上述引⼊的依赖
spring-boot-starter-security
就是
Spring Boot
整合
Spring Security
安全框架⽽提供的依赖启动器,
其版本号由
Spring Boot
进⾏统⼀管理。需要说明的是,⼀旦项⽬引⼊
spring-boot-starter-security
启动器,
MVC
Security
和
WebFlux Security
负责的安全功能都会⽴即⽣效(
WebFlux Security
⽣效的另⼀个前提是项⽬属于
WebFlux Web
项⽬);对于
OAuth2
安全管理功能来说,则还需要额外引⼊⼀些其他安全依赖。
项⽬启动测试
项⽬启动时会在控制台⾃动⽣成⼀个安全密码(
security password
这个密码在每次启动项⽬时都是随机⽣成
的)。通过在浏览器访问
http://localhost:8080
查看项⽬⾸⻚,效果如下图所示。
这种默认安全管理⽅式存在诸多问题。例如,只有唯⼀的默认登录⽤户user
,密码随机⽣成且过于暴露、登录⻚⾯ 及错误提示⻚⾯不是我们想要的等。
1.MVC Security
安全配置介绍
1.下⾯我们通过
Spring Security API
查看
WebSecurityConfigurerAdapter
的主要⽅法,具体如下表
@EnableWebSecurity // 开启MVC Security安全⽀持
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//定制基于HTTP请求的⽤户访问控制
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
}
//定制⽤户认证管理器来实现⽤户认证
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
super.configure(auth);
}
}
4
⾃定义⽤户认证
1.In-Memory Authentication:内存身份认证
2.JDBC Authentication:
JDBC
身份认证
3.UserDetailsService:身份详情服务
4.LDAP Authentication:
LDAP
身份认证
5.AuthenticationProvider:身份认证提供商
4.1.2 使⽤内存进⾏身份认证 写一个配置类即可
package com.cy.config;
import
org.springframework.security.config.annotation.authentication.builders.AuthenticationMa
nagerBuilder;
import
org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import
org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerA
dapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
/**
* MVC Security管理配置的⾃定义WebSecurityConfigurerAdapter类
*/
@EnableWebSecurity // 开启MVC Security安全⽀持
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/** ⽤户身份认证⾃定义配置 */
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// 密码需要设置编码器
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
// 1.使⽤内存⽤户信息,作为测试使⽤(设置⽤户名、密码和⻆⾊)
auth.inMemoryAuthentication().passwordEncoder(encoder)
.withUser("tom").password(encoder.encode("123456")).roles("common")
.and()
.withUser("李四").password(encoder.encode("123456")).roles("vip");
}
}
(1)
从
Spring Security 5
开始,⾃定义⽤户认证必须设置密码编码器⽤于保护密码,否则控制台会出现
“IllegalArgumentException: There is no PasswordEncoder mapped for the id “null””
异常错误。
(2) Spring Security
提供了多种密码编码器,包括
BCryptPasswordEncoder
、
Pbkdf2PasswordEncoder
、
ScryptPasswordEncoder
等。
(3)
⾃定义⽤户认证时,可以定义⽤户⻆⾊
roles
,也可以定义⽤户权限
authorities
。在进⾏赋值时,权限通常是在
⻆⾊值的基础上添加
ROLE_
前缀。例如,
roles(“common”)
和
authorities(“ROLE_common”)
是等效的。
(4)
⾃定义⽤户认证时,可以为某个⽤户⼀次指定多个⻆⾊或权限,例如,
roles(“common”, “vip”)
或
authorities(“ROLE_common”, “ROLE_vip”)
4.3 UserDetailsService
身份认证
1.
1.
在项⽬的
pom.xml
⽂件中添加Mybaits
依赖启动器和
lombok
依赖。
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.2</version> </dependency>
<dependency>
<groupId>
org.projectlombok
</groupId>
<artifactId>
lombok
</artifactId>
</dependency>
package com.example.demo.service.imp;
import com.example.demo.pojo.Authority;
import com.example.demo.pojo.Customer;
import com.example.demo.service.CustomerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
/** ⾃定义⼀个UserDetailsService接⼝实现类进⾏⽤户认证信息封装 */
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
/* 内有提供自定义用户查询和权限查询的方法
* getCustomer 根据名字查询用户信息 的方法
*
* getCustomerAuthority 根据名字查询用户权限 的方法
* */
private CustomerService customerService;
@Override
public UserDetails loadUserByUsername(String username) throws
UsernameNotFoundException {
// 通过业务⽅法获取⽤户及权限信息
Customer customer = customerService.getCustomer(username);
List<Authority> authorities = customerService.getCustomerAuthority(username);
// 对⽤户权限进⾏封装
List<SimpleGrantedAuthority> list = authorities.stream().map(authority -> new
SimpleGrantedAuthority(authority.getAuthority())).collect(Collectors.toList());
// 返回封装的UserDetails⽤户详情类
if (customer != null) {
UserDetails userDetails = new User(customer.getUsername(),
customer.getPassword(), list);
return userDetails;
} else {
// 如果查询的⽤户不存在(⽤户名不存在),必须抛出此异常
throw new UsernameNotFoundException("当前⽤户不存在!");
}}}
package com.example.demo.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
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.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import javax.sql.DataSource;
import java.util.Date;
import java.util.HashMap;
//开启安全管理的支持
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired //Hikari连接池,自动将mysql配置信息加载连接池对象上
private DataSource dataSource;
//1.用户身份认证的配置
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests() // 开启基于HttpServletRequest请求访问的限制
.antMatchers("/").permitAll() // 开启Ant⻛格的路径匹配。⽆条件对请求进⾏放⾏
.antMatchers("/login/**").permitAll()
.antMatchers("/detail/common/**").hasRole("common") // 匹配⽤户是否有某⼀个⻆⾊
.antMatchers("/detail/vip/**").hasRole("vip")
.anyRequest().authenticated()// 匹配任何请求。匹配已经登录认证的⽤户
.and() // 功能连接符
.formLogin(); // 开启基于表单的⽤户登录
http.formLogin() // 开启基于表单的⽤户登录
// ⽤户登录⻚⾯跳转路径,默认为get请求的/login。⽆条件对请求进⾏放⾏
.loginPage("/userLogin").permitAll()
.usernameParameter("name") // 登录⽤户的⽤户名参数, 默认为username
.passwordParameter("pwd") // 登录⽤户的密码参数,默认为password
.defaultSuccessUrl("/") // ⽤户直接登录后默认跳转地址
.failureUrl("/userLogin?error"); // ⽤户登录失败后的跳转地址,默认为/login?erro
// ⾃定义⽤户退出控制
http.logout()
.logoutUrl("/mylogout")
.logoutSuccessUrl("/");
// 定制Remember-me记住我功能
http.rememberMe()
.rememberMeParameter("rememberme")
.tokenValiditySeconds(200)
// 对Cookie信息进⾏持久化管理
.tokenRepository(tokenRepository());
}
@Bean
/** 持久化Token存储 */
public JdbcTokenRepositoryImpl tokenRepository() {
JdbcTokenRepositoryImpl jti = new JdbcTokenRepositoryImpl();
jti.setDataSource(dataSource);
//自动创建数据库表字段
jti.setCreateTableOnStartup(true);
return jti;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// 密码需要设置编码器
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
auth.userDetailsService(userDetailsService).passwordEncoder(encoder);
}
}
完成以上配置基于
内存进⾏身份认证
就结束了
接下来是配置的信息
方法 | 描述 |
---|---|
authorizeRequests() |
开启基于 HttpServletRequest 请求访问的限制 |
formLogin() |
开启基于表单的⽤户登录 |
httpBasic() |
开启基于 HTTP 请求的 Basic 认证登录 |
logout() |
开启退出登录的⽀持 |
sessionManagement() |
开启 Session 管理配置 |
rememberMe() |
开启记住我功能 |
csrf() |
配置 CSRF 跨站请求伪造防护功能 |
⽅法 |
描述 |
---|---|
antMatchers(java.lang.String… antPtterns) |
开启 Ant ⻛格的路径匹配 |
mvcMatchers(java.lang.String… patterns) |
开启 MVC ⻛格的路径匹配(与 Ant ⻛格类似) |
regexMatchers(java.lang.Sring… regexPatterns) |
开启正则表达式的路径匹配 |
and() |
功能连接符 |
anyRequest() |
匹配任何请求 |
rememberMe() |
开启记住我功能 |
access(String attribute) |
匹配给定的 SpEL 表达式计算结果是否为 true |
hasAnyRole(String… roles) |
匹配⽤户是否有参数中的任意⻆⾊ |
hasRole(Sring role) |
匹配⽤户是否有某⼀个⻆⾊ |
hasAnyAuthority(String… authorities) |
匹配⽤户是否有参数中的任意权限 |
hasAuthority(String authority) |
匹配⽤户是否有某⼀个权限 |
authenticated() |
匹配已经登录认证的⽤户 |
fullyAuthenticated() |
匹配完整登录认证的⽤户(⾮ rememberMe 登录⽤ 户) |
hasIpAddress(String ipAddressExpression) |
匹配某 IP 地址的访问请求 |
permitAll() |
⽆条件对请求进⾏放⾏ |
⽅法 |
描述 |
---|---|
loginPage(String loginPage) |
⽤户登录⻚⾯跳转路径,默认为 get 请 求的/login |
successForwardUrl(String forwardUrl) |
⽤户登录成功后的重定向地址 |
successHandler(AuthenticationSuccessHandler authenticationSuccessHandler) |
⽤户登录成功后的处理 |
defaultSuccessUrl(String defaultSuccessUrl) |
⽤户直接登录后默认跳转地址 |
failureForwardUrl(String forwardUrl) |
⽤户登录失败后的重定向地址 |
failureUrl(String authenticationFailureUrl) |
⽤户登录失败后的跳转地址,默认 为 /login?error |
failureHandler(AuthenticationFailureHandler authenticationFailureHandler) |
⽤户登录失败后的错误处理 |
usernameParameter(String usernameParameter) |
登录⽤户的⽤户名参数, 默认为 username |
passwordParameter(String passwordParameter) |
登录⽤户的密码参数,默认为 password |
loginProcessingUrl(String loginProcessingUrl) |
登录表单提交的路径,默认为 post 请 求的 /login |
permitAll() |
permitAll() ⽆条件对请求进⾏放⾏ |
⽅法 |
描述 |
---|---|
rememberMeParameter(String rememberMeParameter) |
指示在登录时记住⽤户的 HTTP 参数 |
key(String key) |
记住我认证⽣成的 Token 令牌标识 |
tokenValiditySeconds(int tokenValiditySeconds) |
记住我 Token 令牌有效期,单位为秒 |
tokenRepository(PersistentTokenRepository tokenRepository) |
指定要使⽤的 PersistentTokenRepository ,⽤来配置持久化 Token 令牌 |
alwaysRemember(boolean alwaysRemember) |
是否应该始终创建记住我 Cookie ,默认为 false |
clearAuthentication(boolean clearAuthentication) |
是否设置 Cookie 为安全的,如果设置为 true ,则必须通过 HTTPS 进⾏连接请 求 |
⽅法 |
描述 |
---|---|
disable() |
关闭 Security 默认开启的 CSRF 防御功能 |
csrfTokenRepository(CsrfTokenRepository csrfTokenRepository) |
指定要使⽤的 CsrfTokenRepository ( Token 令牌持久化仓库)。默认是由 LazyCsrfTokenRepository 包装的 HttpSessionCsrfTokenRepository |
requireCsrfProtectionMatcher(RequestMatcher requireCsrfProtectionMatcher) |
指定针对什么类型的请求应⽤ CSRF 防护功能。默认设置是忽略 GET 、 HEAD 、 TRACE 和 OPTIONS 请 求,⽽处理并防御其他所有请求 |
以上就是一些比较常用的配置信息
版权声明:本文为weixin_62907807原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。