DAY30.1 Java核心基础
Spring Boot 整合安全框架
Spring Security 、Shiro
Spring Security
Spring Security 的核心功能包括认证、授权、攻击防护,通过大量的过滤器和拦截器进行请求的拦截和验证,实现安全校验的功能。
Spring Security 将校验逻辑分发到不同的拦截器中,一个拦截器负责一种验证,比如UsernamePassword拦截器就是专门用来验证用户名和密码是否正确的,它会拦截登入请求,检查是否包含了用户名和密码,同时进行验证,如果没有则放行进入下一个拦截器
1、pom中添加依赖
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2、创建一个index页面
html
<!DOCTYPE html>
<!--导入thymeleaf配置-->
<html lang="en" xmlns:th="http://www.thymeleaf.org"></html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>hello</h1>
</body>
</html>
3、访问页面(如果没登入认证)会跳转到 Spring Security 的登入验证界面

这个页面是Spring Security自带的页面,导入了依赖包就有了
然后用户名密码默认为user,密码为启动的时候生成的密码
然后他在拦截器UsernamePasswordAuthenticationFilter进行拦截验证的
4、配置Spring Security的账号密码
yml
spring:
security:
user:
name: admin
password: 123456
除了登入的时候,Security还可以用于权限验证,比如admin账号可以访问所有页面,user角色账号只能访问某些界面,怎么实现呢?
创建一个配置类SecurityConfig
java
package org.nanfengspringboot01.config;
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;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 定义角色
* @param auth
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().passwordEncoder(new PasswordEncoderImpl())
.withUser("user").password(new PasswordEncoderImpl().encode("123")).roles("USER")
.and()
.withUser("admin").password(new PasswordEncoderImpl().encode("123")).roles("USER","ADMIN");
}
/**
* 定义权限
* @param http
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin").hasRole("ADMIN")
.antMatchers("/index").access("hasRole('ADMIN') or hasRole('USER')")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll()
.and()
.csrf()
.disable();
}
}
还需要一个实现类PasswordEncoderImpl
java
public class PasswordEncoderImpl implements PasswordEncoder {
@Override
public String encode(CharSequence rawPassword) {
return rawPassword.toString();
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return encodedPassword.equals(rawPassword.toString());
}
}
解释一下配置代码:
java
http.authorizeRequests()
开始配置 URL 的访问权限控制。
java
.antMatchers("/admin").hasRole("ADMIN")
访问 /admin
页面必须具备 ADMIN
角色。
java
.antMatchers("/index").access("hasRole('ADMIN') or hasRole('USER')")
访问 /index
页面,要求用户拥有 ADMIN
或 USER
角色中的任意一个。
java
.anyRequest().authenticated()
除了 /admin
和 /index
外,其他所有请求都必须登录后才能访问。
java
.and()
.formLogin()
.loginPage("/login")
.permitAll()
配置表单登录:
- 登录页面为
/login
(你需要自己定义一个该路径的登录页面) - 所有人都可以访问该登录页面(不需要登录)
java
.and()
.logout()
.permitAll()
配置登出功能:
- 所有人都可以访问登出接口
java
.and()
.csrf()
.disable();
禁用 CSRF(跨站请求伪造)防护机制。
✅ 适合前后端分离、或使用 JWT 登录验证的项目。否则生产环境最好不要关闭 CSRF 防护。
控制器
java
@Controller
public class IndexController {
@GetMapping("/index")
private String index(){
return "index";
}
@GetMapping("/admin")
private String admin(){
return "admin";
}
@GetMapping("/login")
private String login(){
return "login";
}
}
访问页面index.html
会自动跳转到login.html登入界面

但是user账户登入之后访问不了admin界面,因为user没有访问admin界面的权限

连接数据库获取账号信息
创建数据库表Account
sql
create table account(
id int PRIMARY key auto_increment,
username VARCHAR(11),
password VARCHAR(11),
role VARCHAR(11)
)
配置用户信息,注意role的写法需要写出ROLE_USER这样的格式,这个是Security的解析格式

创建实体类
java
@Data
@Entity
public class Account {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column
private String username;
@Column
private String password;
@Column
private String role;
}
创建 AccountRepository,实现登录方法
java
@Repository
public interface AccountResitory extends JpaRepository<Account,Integer> {
public Account findByUsername(String username);
}
重写UserDetailsService接口的loadUserByUsername方法,从数据库获取密码 ,返回一个User对象
java
@Service
public class UserDetailServiceImpl implements UserDetailsService {
@Autowired
private AccountResitory accountResitory;
/**
* 通过重新这个方法来改变验证匹配密码的逻辑
* @param username
* @return
* @throws UsernameNotFoundException
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Account account = accountResitory.findByUsername(username);
if(account==null){
throw new UsernameNotFoundException("用户不存在");
}else {
String password = account.getPassword();
Collection<GrantedAuthority> authorities = new ArrayList<>();
SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(account.getRole());
authorities.add(simpleGrantedAuthority);
return new User(username,password,authorities);
}
}
}
修改Security的配置类,将这个UserDetailsService注入
auth.userDetailsService(userDetailService).passwordEncoder(passwordEncoder());
java
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailService;
/**
* 定义用户角色
* @param auth
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// auth.inMemoryAuthentication().passwordEncoder(new PasswordEncoderImpl())
// .withUser("user").password(new PasswordEncoderImpl().encode("123")).roles("USER")
// .and()
// .withUser("admin").password(new PasswordEncoderImpl().encode("123")).roles("USER","ADMIN");
auth.userDetailsService(userDetailService).passwordEncoder(passwordEncoder());
}
@Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
/**
* 定义权限
* @param http
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin").hasRole("ADMIN")
.antMatchers("/index").access("hasRole('ADMIN') or hasRole('USER')")
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/login").permitAll()
.and()
.logout().permitAll()
.and()
.csrf().disable();
}
}