Spring Security提供了多种密码编码器实现,推荐使用BCryptPasswordEncoder作为默认选择。
+ * + *特点:
+ *注意:不推荐使用MD5等弱哈希算法,Spring官方也不推荐自定义弱密码编码器。
+ * + * @return PasswordEncoder 密码编码器实例 + * @see BCryptPasswordEncoder + */ + @Bean + public PasswordEncoder passwordEncoder() { + // 其他编码器示例(根据需求选择一种): + // return new Argon2PasswordEncoder(16, 32, 1, 1 << 14, 2); + // return new SCryptPasswordEncoder(); + // return new Pbkdf2PasswordEncoder("secret", 185000, 256); + + // 实际项目中只需返回一个密码编码器 + return new BCryptPasswordEncoder(); + } +} diff --git a/spring-security/step-2/src/main/java/com/spring/security/config/SecurityWebConfiguration.java b/spring-security/step-2/src/main/java/com/spring/security/config/SecurityWebConfiguration.java new file mode 100644 index 0000000..ec537d2 --- /dev/null +++ b/spring-security/step-2/src/main/java/com/spring/security/config/SecurityWebConfiguration.java @@ -0,0 +1,65 @@ +package com.spring.security.config; + +import com.spring.security.handler.SecurityAccessDeniedHandler; +import com.spring.security.handler.SecurityAuthenticationEntryPoint; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; +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.configurers.AbstractHttpConfigurer; +import org.springframework.security.web.SecurityFilterChain; + +@EnableMethodSecurity +@EnableWebSecurity +@Configuration +public class SecurityWebConfiguration { + + @Bean + SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + String[] permitAllUrls = { + "/", "/doc.html/**", + "/webjars/**", "/images/**", ".well-known/**", "favicon.ico", "/error/**", + "/swagger-ui/**", "/v3/api-docs/**" + }; + + http.authorizeHttpRequests(authorizeRequests -> + // 访问路径为 /api 时需要进行认证 + authorizeRequests + .requestMatchers(permitAllUrls).permitAll() + .requestMatchers("/api/security/**").permitAll() + .requestMatchers(HttpMethod.GET, "/api/anonymous/**").anonymous() + // 会自动变成 ROLE_ADMIN + // .requestMatchers("/api/**").hasRole("ADMIN") + .requestMatchers("/api/**").hasAnyAuthority("all", "read") + ) + .formLogin(loginPage -> loginPage + // 自定义登录页路径 + .loginPage("/login-page") + // 处理登录的URL(默认就是/login) + .loginProcessingUrl("/login") + // 登录成功跳转 + .defaultSuccessUrl("/") + // 登录失败跳转 + .failureUrl("/login-page?error=true") + .permitAll() + ) + // 使用默认的登录 + // .formLogin(Customizer.withDefaults()) + // 禁用表单登录 + // .formLogin(AbstractHttpConfigurer::disable) + .logout(logout -> logout + .logoutSuccessUrl("/login-page?logout=true") + .permitAll() + ) + .csrf(AbstractHttpConfigurer::disable) + .exceptionHandling(configurer -> configurer + .accessDeniedHandler(new SecurityAccessDeniedHandler()) + .authenticationEntryPoint(new SecurityAuthenticationEntryPoint()) + ) + ; + + return http.build(); + } +} \ No newline at end of file diff --git a/spring-security/step-2/src/main/java/com/spring/security/handler/SecurityAccessDeniedHandler.java b/spring-security/step-2/src/main/java/com/spring/security/handler/SecurityAccessDeniedHandler.java new file mode 100644 index 0000000..661e686 --- /dev/null +++ b/spring-security/step-2/src/main/java/com/spring/security/handler/SecurityAccessDeniedHandler.java @@ -0,0 +1,28 @@ +package com.spring.security.handler; + +import com.alibaba.fastjson2.JSON; +import com.spring.bean.vo.result.Result; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.web.access.AccessDeniedHandler; + +import java.io.IOException; + +@Slf4j +public class SecurityAccessDeniedHandler implements AccessDeniedHandler { + @Override + public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException { + log.error("CustomerAccessDeniedHandler:{}", accessDeniedException.getLocalizedMessage()); + + Result