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

}
相关推荐
GreenTea14 小时前
一文搞懂Harness Engineering与Meta-Harness
前端·人工智能·后端
我是大猴子16 小时前
Spring代理类为何依赖注入失效?
java·后端·spring
码事漫谈16 小时前
手把手带你部署本地模型,让你Token自由(小白专属)
前端·后端
码农BookSea17 小时前
ReAct:让大模型学会边想边做
后端·ai编程
码农BookSea18 小时前
10分钟掌握 JSON-RPC 协议,面试加分、设计不踩坑
后端
Java成神之路-18 小时前
通俗易懂理解 Spring MVC 拦截器:概念、流程与简单实现(Spring系列16)
java·spring·mvc
凤年徐18 小时前
C++手撕红黑树:从0到200行,拿下STL map底层核心
c++·后端·算法
IT_陈寒18 小时前
Python的列表推导式里藏了个坑,差点让我加班到凌晨
前端·人工智能·后端
递归尽头是星辰18 小时前
Spring Boot 配置排除失效深度解析:时序与机制核心
spring boot·自动配置·bean 加载·exclude失效·组件扫描
卷无止境19 小时前
podman与docker的区别和生产环境最佳实践
后端