跳转到主内容
新派编程网 - 新潮编程理念,全新技术课堂!

Java中Spring Security的使用及最佳实践

目录1. Spring Security 简介

2. 快速开始

2.1 添加依赖2.2 基本配置

3. 详细配置

3.1 认证配置内存认证JDBC 认证(可选)自定义 UserDetailsService 3.2 授权配置3.3 密码加密

4. 高级特性

4.1 CSRF 防护4.2 方法级安全4.3 OAuth2 集成4.4 JWT 集成

5. 测试安全配置

5.1 测试控制器5.2 测试安全配置

6. 最佳实践

7. 常见问题解决

7.1 自定义登录页面7.2 处理 AccessDeniedException 7.3 多 HTTP 安全配置

8. 总结

1. Spring Security 简介Spring Security 是一个功能强大且高度可定制的身份验证和访问控制框架,它是 Spring 生态系统中的标准安全框架。主要提供以下功能:认证(Authentication):验证用户身份授权(Authorization):控制用户访问权限防护攻击:防止 CSRF、会话固定等攻击与其他技术集成:如 OAuth2、LDAP 等

2. 快速开始

2.1 添加依赖对于 Maven 项目,在pom.xml

中添加:

org.springframework.bootspring-boot-starter-security对于 Gradle 项目:implementation 'org.springframework.boot:spring-boot-starter-security'2.2 基本配置创建一个配置类继承WebSecurityConfigurerAdapter:@Configuration@EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter {@Override protected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/", "/home").permitAll().anyRequest().authenticated().and().formLogin().loginPage("/login").permitAll().and().logout().permitAll();}@Bean@Override public UserDetailsService userDetailsService() {UserDetails user = User.withDefaultPasswordEncoder().username("user").password("password").roles("USER").build();return new InMemoryUserDetailsManager(user);}}

3. 详细配置

3.1 认证配置内存认证WebSecurityConfigurerAdapter.java@Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {auth.inMemoryAuthentication().withUser("user").password("{noop}password").roles("USER").and().withUser("admin").password("{noop}admin").roles("ADMIN");}JDBC 认证(可选) WebSecurityConfigurerAdapter.java@Autowired private DataSource dataSource;@Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {auth.jdbcAuthentication().dataSource(dataSource).usersByUsernameQuery("select username,password,enabled from users where username=?").authoritiesByUsernameQuery("select username,authority from authorities where username=?");}自定义 UserDetailsService@Service public class CustomUserDetailsService implements UserDetailsService {@Autowired private UserRepository userRepository;@Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {User user = userRepository.findByUsername(username).orElseThrow(() -> new UsernameNotFoundException("User not found"));return new org.springframework.security.core.userdetails.User(user.getUsername(),user.getPassword(),getAuthorities(user.getRoles()));}private Collection getAuthorities(Collection roles) {return roles.stream().map(role -> new SimpleGrantedAuthority(role.getName())).collect(Collectors.toList());}}3.2 授权配置WebSecurityConfigurerAdapter.java@Override protected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/admin/**").hasRole("ADMIN").antMatchers("/user/**").hasAnyRole("USER", "ADMIN").antMatchers("/public/**").permitAll().anyRequest().authenticated().and().formLogin().loginPage("/login").defaultSuccessUrl("/dashboard").failureUrl("/login?error=true").permitAll().and().logout().logoutUrl("/logout").logoutSuccessUrl("/login?logout=true").invalidateHttpSession(true).deleteCookies("JSESSIONID").permitAll().and().rememberMe().key("uniqueAndSecret").tokenValiditySeconds(86400);}3.3 密码加密推荐使用 BCrypt 密码编码器:

WebSecurityConfigurerAdapter.java@Bean public PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}

然后在用户注册时加密密码:

WebSecurityConfigurerAdapter.java@Autowired private PasswordEncoder passwordEncoder;public void registerUser(User user) {user.setPassword(passwordEncoder.encode(user.getPassword()));userRepository.save(user);}

4. 高级特性

4.1 CSRF 防护Spring Security 默认启用 CSRF 防护。在表单中添加 CSRF 令牌:

或者在 AJAX 请求中添加:var token = $("meta[name='_csrf']").attr("content");var header = $("meta[name='_csrf_header']").attr("content");$(document).ajaxSend(function(e, xhr, options) {xhr.setRequestHeader(header, token);});4.2 方法级安全

启用方法级安全:

@Configuration@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true,jsr250Enabled = true) public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {}

然后在方法上使用注解:

@PreAuthorize("hasRole('ADMIN')") public void deleteUser(Long userId) {// ...

}@PostAuthorize("returnObject.owner == authentication.name") public Document getDocument(Long docId) {// ...

}@Secured("ROLE_ADMIN") public void updateUser(User user) {// ...

}4.3 OAuth2 集成

添加依赖:

org.springframework.bootspring-boot-starter-oauth2-client配置 OAuth2 客户端:spring:security:oauth2:client:registration:google:client-id: your-client-id client-secret: your-client-secret scope: email, profile4.4 JWT 集成

添加依赖:

io.jsonwebtokenjjwt0.9.1创建 JWT 工具类:public class JwtTokenUtil {private String secret = "your-secret-key";private long expiration = 86400000; // 24小时public String generateToken(UserDetails userDetails) {Map claims = new HashMap<>();return Jwts.builder().setClaims(claims).setSubject(userDetails.getUsername()).setIssuedAt(new Date()).setExpiration(new Date(System.currentTimeMillis() + expiration)).signWith(SignatureAlgorithm.HS512, secret).compact();}public Boolean validateToken(String token, UserDetails userDetails) {final String username = getUsernameFromToken(token);return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));}// 其他工具方法...

}配置 JWT 过滤器:public class JwtRequestFilter extends OncePerRequestFilter {@Autowired private CustomUserDetailsService userDetailsService;@Autowired private JwtTokenUtil jwtTokenUtil;@Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {final String authorizationHeader = request.getHeader("Authorization");String username = null;String jwt = null;if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {jwt = authorizationHeader.substring(7);username = jwtTokenUtil.getUsernameFromToken(jwt);}if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);if (jwtTokenUtil.validateToken(jwt, userDetails)) {UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));SecurityContextHolder.getContext().setAuthentication(authentication);}}chain.doFilter(request, response);}}

在安全配置中添加过滤器:

@Override protected void configure(HttpSecurity http) throws Exception {http.csrf().disable().authorizeRequests().antMatchers("/authenticate").permitAll().anyRequest().authenticated().and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);}

5. 测试安全配置

5.1 测试控制器@RestController public class TestController {@GetMapping("/admin")@PreAuthorize("hasRole('ADMIN')") public String adminAccess() {return "Admin Board";}@GetMapping("/user")@PreAuthorize("hasRole('USER') or hasRole('ADMIN')") public String userAccess() {return "User Content";}@GetMapping("/all") public String allAccess() {return "Public Content";}}5.2 测试安全配置@SpringBootTest@AutoConfigureMockMvc public class SecurityTest {@Autowired private MockMvc mockMvc;@Test@WithMockUser(username = "user", roles = {"USER"}) public void givenUserRole_whenAccessUserEndpoint_thenOk() throws Exception {mockMvc.perform(get("/user")).andExpect(status().isOk());}@Test@WithMockUser(username = "user", roles = {"USER"}) public void givenUserRole_whenAccessAdminEndpoint_thenForbidden() throws Exception {mockMvc.perform(get("/admin")).andExpect(status().isForbidden());}@Test public void givenUnauthenticated_whenAccessPublicEndpoint_thenOk() throws Exception {mockMvc.perform(get("/all")).andExpect(status().isOk());}}

6. 最佳实践

最小权限原则:只授予必要的权限密码安全:始终使用强密码哈希算法(如 BCrypt)

HTTPS:在生产环境中强制使用 HTTPS安全头:启用安全头(如 X-Frame-Options, X-XSS-Protection 等)

定期更新:保持 Spring Security 版本更新审计日志:记录重要的安全事件输入验证:不要依赖 Spring Security 进行所有输入验证

7. 常见问题解决

7.1 自定义登录页面@Override protected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/login*").permitAll().anyRequest().authenticated().and().formLogin().loginPage("/login.html").loginProcessingUrl("/perform_login").defaultSuccessUrl("/home.html", true).failureUrl("/login.html?error=true");}7.2 处理 AccessDeniedException

创建自定义访问拒绝处理器:

@Component public class CustomAccessDeniedHandler implements AccessDeniedHandler {@Override public void handle(HttpServletRequest request, HttpServletResponse response,AccessDeniedException accessDeniedException) throws IOException, ServletException {response.sendRedirect(request.getContextPath() + "/access-denied");}}

然后在配置中使用:

@Override protected void configure(HttpSecurity http) throws Exception {http.exceptionHandling().accessDeniedHandler(accessDeniedHandler);}7.3 多 HTTP 安全配置@Configuration@Order(1) public class ApiSecurityConfig extends WebSecurityConfigurerAdapter {@Override protected void configure(HttpSecurity http) throws Exception {http.antMatcher("/api/**").authorizeRequests().anyRequest().hasRole("API_USER").and().httpBasic();}}@Configuration public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Override protected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().authenticated().and().formLogin();}}

8. 总结

Spring Security 是一个功能全面且灵活的安全框架,本教程涵盖了从基础配置到高级特性的主要内容。实际应用中,应根据具体需求选择合适的认证和授权方式,并遵循安全最佳实践。

对于更复杂的场景,建议参考Spring Security 官方文档和社区资源。

到此这篇关于Java中Spring Security的使用的文章就介绍到这了,更多相关Spring Security使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:Java中Spring的Security使用详解Java 中使用Spring Security的实例详解java SpringSecurity使用详解Spring Security常用配置的使用解读springboot security使用jwt认证方式SpringSecurity中内置过滤器的使用小结SpringSecurity在分布式环境下的使用流程分析SpringSecurity中PasswordEncoder的使用spring-boot-starter-security的简单使用方式

相关文章