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();
    }

}
相关推荐
后端小张8 小时前
【JAVA 进阶】深入拆解SpringBoot自动配置:从原理到实战的完整指南
java·开发语言·spring boot·后端·spring·spring cloud·springboot
草莓熊Lotso8 小时前
C++11 核心进阶:引用折叠、完美转发与可变参数模板实战
开发语言·c++·人工智能·经验分享·后端·visualstudio·gitee
Q_Q5110082858 小时前
小程序springBoot新农村综合风貌旅游展示平台
vue.js·spring boot·后端
风象南8 小时前
Docker 容器实现按顺序启动
后端
BingoGo8 小时前
10 个强大且值得掌握的 Linux 命令
后端
czlczl2002092510 小时前
告别 try-catch 地狱:Spring Boot 全局异常处理 (GlobalExceptionHandler) 最佳实践
java·spring boot·后端
神奇的程序员15 小时前
从已损坏的备份中拯救数据
运维·后端·前端工程化
oden16 小时前
AI服务商切换太麻烦?一个AI Gateway搞定监控、缓存和故障转移(成本降40%)
后端·openai·api
ะัี潪ิื16 小时前
springboot加载本地application.yml和加载Consul中的application.yml配置反序列化LocalDate类型差异
spring boot·consul·java-consul