spring boot 3集成spring security6

1、maven依赖

复制代码
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

如果需要JDBC的动态数据认证则需要加如下

复制代码
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
            <version>3.2.0</version>
        </dependency>

        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>

密码加密依赖

复制代码
<dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk18on</artifactId>
            <version>1.82</version>
        </dependency>

2、配置文件

复制代码
spring:
  application:
    name: serurity

  datasource:
    url: jdbc:mysql://localhost:3306/security_test
    username: root
    password: 123abc?
    driver-class-name: com.mysql.cj.jdbc.Driver

3、如果使用jdbc数据库用户认证 则需要新建数据表(用户表users和权限表authorities),

用户表字段

权限表字段

4、新建用户管理类UserManagementConfig

复制代码
package com.example.serurity.config;

import com.example.serurity.test.SimpleUser;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.*;
import org.springframework.security.crypto.scrypt.SCryptPasswordEncoder;
import org.springframework.security.provisioning.JdbcUserDetailsManager;
import org.springframework.security.provisioning.UserDetailsManager;

import javax.sql.DataSource;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Configuration
public class UserManagementConfig {

    //用户详情服务
//    @Bean
//    public UserDetailsService userDetailsService() {
//
//        InMemoryUserDetailsManager userDetailsService = new InMemoryUserDetailsManager();
//
//        UserDetails user= User.withUsername("john")
//                .password("12345")
//                .authorities("read").build();
//
//
//        userDetailsService.createUser(user);
//
//        return userDetailsService;
//    }

//    @Bean
//    public UserDetailsService userDetailsService() {
//        //自定义练习
//        UserDetails userDetails=new SimpleUser("john","127345","read");
//        return new InMemoryUserDetailsService(List.of(userDetails));
//    }

    @Bean
    public UserDetailsService userDetailsService(DataSource dataSource) {

        String usersByUsernameQuery = "select username,password,enabled from users where enabled=1 and username = ?";
        String authsByUserQuery="select username,authority from authorities where username = ?";
        JdbcUserDetailsManager jdbcUserDetailsManager = new JdbcUserDetailsManager(dataSource);

        jdbcUserDetailsManager.setUsersByUsernameQuery(usersByUsernameQuery);
        jdbcUserDetailsManager.setAuthoritiesByUsernameQuery(authsByUserQuery);


        return jdbcUserDetailsManager;
    }


    //密码编码
    @Bean
    public PasswordEncoder passwordEncoder() throws NoSuchAlgorithmException {

        //方式1
//        return Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_8();

        //方式2
//        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
//        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder(4);
//        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder(4, SecureRandom.getInstanceStrong());
//        return bCryptPasswordEncoder;

        //方式3
//        SCryptPasswordEncoder sCryptPasswordEncoder = SCryptPasswordEncoder.defaultsForSpringSecurity_v5_8();
//        return sCryptPasswordEncoder;
        //方式4

        Map<String, PasswordEncoder> encoderMap=new LinkedHashMap<>();
        encoderMap.put("bcrypt", new BCryptPasswordEncoder());
        encoderMap.put("scrypt", SCryptPasswordEncoder.defaultsForSpringSecurity_v5_8());
        encoderMap.put("noop",NoOpPasswordEncoder.getInstance());

        return new DelegatingPasswordEncoder("scrypt",encoderMap);

    }

}

5、新建身份验证提供程序类CustomAuthenticationProvider

复制代码
package com.example.serurity.service_config;

import jakarta.annotation.Resource;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

//    AuthenticationManager

    @Resource
    @Lazy
    private UserDetailsService userDetailsService;

    @Resource
    @Lazy
    private PasswordEncoder passwordEncoder;

    @Override
    public Authentication authenticate(Authentication authentication)  {
        String username = authentication.getName();
        String password = authentication.getCredentials().toString();
        UserDetails user = userDetailsService.loadUserByUsername(username);
         if(passwordEncoder.matches(password,user.getPassword())){
            return new UsernamePasswordAuthenticationToken(username,password,user.getAuthorities());
        }else {
            throw new BadCredentialsException("密码不正确");
        }
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }
}

6、新建跨域配置类CorsConfig

复制代码
package com.example.serurity.config;

import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;

import java.util.List;

public class CorsConfig implements CorsConfigurationSource {

    //全局跨域配置
    @Override
    public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowedOrigins(List.of("http://localhost:4200"));
        //config.addAllowedOrigin("*");
        config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE"));
        return config;
    }
}

7、新建Basic验证失败执行类CustomEntryPoint

复制代码
package com.example.serurity.handler;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;

import java.io.IOException;

public class CustomEntryPoint implements AuthenticationEntryPoint {
    //身份验证失败时,执行
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        response.addHeader("message","I am you father");
        response.sendError(HttpStatus.UNAUTHORIZED.value());
    }
}

9、新建身份验证类,整合所有的配置类WebAuthenticationConfig

复制代码
package com.example.serurity.config;

import com.example.serurity.filter.AuthenticationLoggingFilter;
import com.example.serurity.filter.CsrfTokenLogger;
import com.example.serurity.filter.RequestValidationFilter;
import com.example.serurity.handler.CustomCsrfTokenRepository;
import com.example.serurity.handler.CustomEntryPoint;
import com.example.serurity.service_config.CustomAuthenticationProvider;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpMethod;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.expression.WebExpressionAuthorizationManager;
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.csrf.CsrfFilter;
import org.springframework.security.web.csrf.CsrfTokenRepository;
import org.springframework.security.web.csrf.DefaultCsrfToken;
import org.springframework.security.web.util.matcher.RegexRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;

import java.util.List;

@Configuration
@EnableWebSecurity
public class WebAuthenticationConfig {

    @Resource
    @Lazy
    private CustomAuthenticationProvider customAuthenticationProvider;

    //授权
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {


        //access的自定义表达式
//        AuthorizationManager<RequestAuthorizationContext> authorizationManager=new WebExpressionAuthorizationManager("""
//            hasRole("ADMIN") && !hasRole("MANAGER")
//        """);
        //配置允许12点之后进行访问
        AuthorizationManager<RequestAuthorizationContext> authorizationManager=new WebExpressionAuthorizationManager("""
            T(java.time.LocalTime).now().isAfter(T(java.time.LocalTime).of(12,0))
        """);


        //正则表达式
        RequestMatcher regexRequestMatcher = new RegexRequestMatcher("^/api/v1/.*",null);

//        http.addFilterBefore(new RequestValidationFilter(), BasicAuthenticationFilter.class)
//                        .addFilterAfter(new AuthenticationLoggingFilter(), BasicAuthenticationFilter.class);
//        http.addFilterAfter(new CsrfTokenLogger(), CsrfFilter.class);
        http.httpBasic(c->{
            c.realmName("OTHER");
            c.authenticationEntryPoint(new CustomEntryPoint());
        }).authorizeHttpRequests(auth -> auth
                        .requestMatchers("/hello").hasRole("ADMIN")
                        .anyRequest().authenticated()
//                .requestMatchers(HttpMethod.POST,"/hello/*").hasRole("ADMIN")
//                .requestMatchers(regexRequestMatcher).hasRole("ADMIN")
        ).authenticationProvider(customAuthenticationProvider);

        http.csrf(v->{
            v.csrfTokenRepository(new CustomCsrfTokenRepository());
            v.ignoringRequestMatchers("/helloPost");
        });
        //跨域
        http.cors(c->{
            c.configurationSource(new CorsConfig());
        });
        return http.build();
    }

}
相关推荐
犯困的饭团6 分钟前
3_【自动化引擎Ansible Runner】深入功能模块 - 不止于 Playbook
后端
写Cpp的小黑黑7 分钟前
WHEP 拉流技术详解(基于一个 html/js demo)
后端
GetcharZp8 分钟前
告别 Selenium!这款 Go 语言神器,让网页自动化与爬虫快到飞起!
后端
天下无贼9 分钟前
【Python】2026版——FastAPI 框架快速搭建后端服务
后端·python·aigc
橙序员小站12 分钟前
当所有人都在做 Agent,我想聊聊被遗忘的基础设施
后端·开源·aigc
小蚂蚁i12 分钟前
LangChain 完全学习手册:看完就能上手
后端·python·ai编程
Memory_荒年14 分钟前
TiDB:当 MySQL 遇上分布式,生了个“超级混血儿”
java·数据库·后端
asom2217 分钟前
DDD(领域驱动设计) 核心概念详解
java·开发语言·数据库·spring boot
一步一个脚印一个坑26 分钟前
用 APM 全链路追踪,29ms 内定位到 Docker 部署的 SSL 配置错误
javascript·后端·监控
aircrushin42 分钟前
端到端AI决策架构如何重塑实时协作体验?
前端·javascript·后端