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();
        }
}
相关推荐
四谎真好看4 小时前
Java 黑马程序员学习笔记(进阶篇18)
java·笔记·学习·学习笔记
桦说编程4 小时前
深入解析CompletableFuture源码实现(2)———双源输入
java·后端·源码
java_t_t4 小时前
ZIP工具类
java·zip
lang201509285 小时前
Spring Boot优雅关闭全解析
java·spring boot·后端
pengzhuofan5 小时前
第10章 Maven
java·maven
百锦再6 小时前
Vue Scoped样式混淆问题详解与解决方案
java·前端·javascript·数据库·vue.js·学习·.net
刘一说6 小时前
Spring Boot 启动慢?启动过程深度解析与优化策略
java·spring boot·后端
壹佰大多6 小时前
【spring如何扫描一个路径下被注解修饰的类】
java·后端·spring
百锦再6 小时前
对前后端分离与前后端不分离(通常指服务端渲染)的架构进行全方位的对比分析
java·开发语言·python·架构·eclipse·php·maven
DokiDoki之父7 小时前
Spring—注解开发
java·后端·spring