Spring Boot 整合 Spring Security

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 页面,要求用户拥有 ADMINUSER 角色中的任意一个。

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();
        }
}
相关推荐
刘大浪7 分钟前
JDK17 与JDK8 共同存在一个电脑上
java
秋难降30 分钟前
贪心算法:看似精明的 “短视选手”,用好了也能逆袭!💥
java·算法
阿蒙Amon33 分钟前
C#数字金额转中文大写金额:代码解析
java·mysql·c#
失乐园36 分钟前
电商/物流/IoT三大场景:用MongoDB设计高扩展数据架构的最佳实践
java·后端·架构
五行星辰38 分钟前
Spring AI 实战:用 Java 搞 AI,从此告别调参侠
java·后端
知其然亦知其所以然42 分钟前
不懂 Python?没关系!Easy RAG 让 Java 开发者也能玩转大模型
java·后端·llm
五行星辰43 分钟前
Spring AI 实现 MCP:让 AI 自动管理你的代码质量
java·后端
shangjg31 小时前
Kafka ACK机制详解:数据可靠性与性能的权衡之道
java·数据库·分布式·后端·kafka
王翼鹏1 小时前
Spring boot 策略模式
java·spring boot·策略模式
lagrahhn1 小时前
记一次idea中lombok无法使用的解决方案
java·ide·intellij-idea