一 .项目启动
在项目中若添加SpringSecurity的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
启动项目时会默认拦截所有的请求,要求必须登录之后才能进行相应的访问
二.SpringSecurity本质是一个过滤链
1.FilterSecurityInterceptor最底端过滤器是一个方法级的过滤器
2.ExcpetionTranslationFilter:是个异常过滤器,用来处理认证需求出现的异常
3.UsernamePassAuthenticationFilter:对/login的Post请求做拦截,校验表单中的用户名,密码。
三.两个重要的接口
UseDetailService 查询数据库用户名密码
PasswordEncoding数据加密,用于返回User对象中的密码加密
四.web权限方案
1.设置登录的用户名和密码通过配置文件
通过配置类自定义用户名密码,首先创建配置类
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(password());
}
@Bean
public PasswordEncoder password() {
return new BCryptPasswordEncoder() ;
}
}
创建MyUserdetaiService 实现UserService接口
@Service("userDetailsService")
public class MyUserDetailService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return new User("ming", new BCryptPasswordEncoder().encode("123"), AuthorityUtils.commaSeparatedStringToAuthorityList("role"));
}
}
五.自定义登录界面
载配置类中进行相关的实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/user/login" method="post">
用户名 : <input type="text" name="username"><br>
密码: <input type="password" name="password"><br>
<input type="submit" value="login">
</form>
</body>
</html>
在配置类中添加
@Override
protected void configure(HttpSecurity http) throws Exception {
//自定义登录界面
http.formLogin().loginPage("/login.html") //登录页面设置
.loginProcessingUrl("/user/login") //登录提交到哪个controller
.defaultSuccessUrl("/index").permitAll() //登录成功后跳转的路径
.and().authorizeRequests().antMatchers("/","/hello","/user/login").permitAll()//设置哪些路径可以直接访问不需要认证
.anyRequest().authenticated() //所有请求都需要认证
.and().csrf().disable(); //关闭csrf防护模式
}
@RestController
public class LoginController {
@RequestMapping("/hello")
public String login(){
return "hello security";
}
@GetMapping("/index")
public String index(){
return "hello index";
}
}
1.hasAuthority的配置
首先在SpringSecurity配置类中加入 .antMatchers("/index").hasAuthority("admins")
然后在MyUserDetailService中加入 AuthorityUtils.commaSeparatedStringToAuthorityList("admin")
此时会报 There was an unexpected error (type=Forbidden, status=403).因为该用户没有admins的权限 将admin改为admins就可以访问了
2.hasAnyAuthority 针对多个用户
antMatchers("/index").hasAnyAuthority("admins,manager") 该用户只要有任何一个权限就可以访问
3.hasRole
.antMatchers("/index").hasRole("sale")
AuthorityUtils.commaSeparatedStringToAuthorityList("admins,ROLE_sale"));
此时注意用户权限中要加入"ROLE"
在源码中可以看到
private static String hasRole(String role) {
Assert.notNull(role, "role cannot be null");
if (role.startsWith("ROLE_")) {
throw new IllegalArgumentException(
"role should not start with 'ROLE_' since it is automatically inserted. Got '"
+ role + "'");
}
return "hasRole('ROLE_" + role + "')";
}
4.hasAnyRole表示角色用于任何一权限都可以
六.自定义403界面
//自定义403界面
http.exceptionHandling().accessDeniedPage("/unsuccessful.html");
七.SpringSecurity认证和授权
1.Secured
首先要在启动类或配置类中加入 @EnableGlobalMethodSecurity(securedEnabled = true)注解
然后在Controller类中加入 @GetMapping("/update")
@Secured({"ROLE_sale","ROLE_manager"})
public String update(){
return "hello update";
}
2. PreAuthorize在方法执行前认证(需要开启@EnableGlobalMethodSecurity(prePostEnabled = true))
@GetMapping("/update2")
@PreAuthorize("hasAuthority('admins')")
public String update2(){
return "hello update";
}
3.在方法执行后认证
2. PostAuthorize在方法执行后认证(需要开启@EnableGlobalMethodSecurity(prePostEnabled = true))
@GetMapping("/update3")
@PostAuthorize("hasAuthority('admin')")
public String update3(){
System.out.println("正常访问");
return "hello update";
}
4.@PostFilter("filterObject.username=="admin")对方法返回值进行过滤
5.@PreFileter 对参数进行过滤
对admin2进行了过滤只输出了admin1
八.自定义退出界面
```java
//自定义退出界面
http.logout().logoutUrl("/logout").logoutSuccessUrl("hello").permitAll();``
九自动登录
首先创建数据库表
CREATE TABLE `persistent_logins` (
`username` varchar(64) NOT NULL,
`series` varchar(64) NOT NULL,
`token` varchar(64) NOT NULL,
`last_used` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`series`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
修改配置类
package com.cp.springsecurity.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
import javax.sql.DataSource;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
//注入数据源
@Autowired
private DataSource dataSource;
@Bean
public PersistentTokenRepository psistentTokenRepository(){
JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
jdbcTokenRepository.setDataSource(dataSource);
//jdbcTokenRepository.setCreateTableOnStartup(true);
return jdbcTokenRepository;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(password());
}
@Bean
public PasswordEncoder password() {
return new BCryptPasswordEncoder() ;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//自定义403界面
http.exceptionHandling().accessDeniedPage("/unsuccessful.html");
//自定义退出界面
http.logout().logoutUrl("/logout").logoutSuccessUrl("/hello").permitAll();
//自定义登录界面
http.formLogin().loginPage("/login.html") //登录页面设置
.loginProcessingUrl("/user/login") //登录提交到哪个controller
.defaultSuccessUrl("/index").permitAll() //登录成功后跳转的路径
.and().authorizeRequests().antMatchers("/","/hello","/user/login").permitAll()//设置哪些路径可以直接访问不需要认证
//表示当前登录只有具有admins权限才可以访问这个路径
// .antMatchers("/index").hasAuthority("admins")
//.antMatchers("/index").hasAnyAuthority("admins,manager")
.antMatchers("/index").hasRole("sales")
.anyRequest().authenticated() //所有请求都需要认证
.and() .rememberMe().tokenRepository(psistentTokenRepository())
.tokenValiditySeconds(60)//设置有效市场60秒
.userDetailsService(userDetailsService)
.and().csrf().disable();//关闭csrf防护模式
}
}
结束语
本文是根据B站up主尚硅谷分享的视频,进行学习整理他的视频链接为
https://www.bilibili.com/video/BV15a411A7kP?p=40