使用Spring Boot与Spring Security构建安全的RESTful API

使用Spring Boot与Spring Security构建安全的RESTful API

引言

在现代Web应用开发中,安全性是不可忽视的重要环节。Spring Boot和Spring Security作为Java生态中的主流框架,为开发者提供了强大的工具来构建安全的RESTful API。本文将详细介绍如何结合Spring Boot和Spring Security,并利用JWT(JSON Web Token)实现身份验证与授权。

技术栈

  • 核心框架: Spring Boot, Spring Security
  • 身份验证: JWT
  • 数据库: H2 (示例)
  • 构建工具: Maven

项目初始化

首先,使用Spring Initializr创建一个新的Spring Boot项目,添加以下依赖:

  • Spring Web
  • Spring Security
  • H2 Database (用于示例)
  • JWT库 (如jjwt)
xml 复制代码
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-api</artifactId>
        <version>0.11.5</version>
    </dependency>
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-impl</artifactId>
        <version>0.11.5</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-jackson</artifactId>
        <version>0.11.5</version>
        <scope>runtime</scope>
    </dependency>
</dependencies>

配置Spring Security

Spring Security默认会为所有端点启用基本认证。我们需要自定义配置以实现JWT认证。

  1. 创建一个配置类SecurityConfig
java 复制代码
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .authorizeRequests()
            .antMatchers("/api/auth/**").permitAll()
            .anyRequest().authenticated()
            .and()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
    }

    @Bean
    public JwtAuthenticationFilter jwtAuthenticationFilter() {
        return new JwtAuthenticationFilter();
    }
}
  1. 实现JWT生成与验证的逻辑:
java 复制代码
@Component
public class JwtTokenProvider {

    @Value("${jwt.secret}")
    private String jwtSecret;

    @Value("${jwt.expiration}")
    private int jwtExpirationInMs;

    public String generateToken(Authentication authentication) {
        UserPrincipal userPrincipal = (UserPrincipal) authentication.getPrincipal();
        Date now = new Date();
        Date expiryDate = new Date(now.getTime() + jwtExpirationInMs);

        return Jwts.builder()
                .setSubject(Long.toString(userPrincipal.getId()))
                .setIssuedAt(new Date())
                .setExpiration(expiryDate)
                .signWith(SignatureAlgorithm.HS512, jwtSecret)
                .compact();
    }

    public Long getUserIdFromJWT(String token) {
        Claims claims = Jwts.parser()
                .setSigningKey(jwtSecret)
                .parseClaimsJws(token)
                .getBody();

        return Long.parseLong(claims.getSubject());
    }

    public boolean validateToken(String authToken) {
        try {
            Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(authToken);
            return true;
        } catch (Exception ex) {
            // Log error
        }
        return false;
    }
}

实现认证与授权

  1. 创建用户服务类CustomUserDetailsService
java 复制代码
@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 with username: " + username));

        return UserPrincipal.create(user);
    }
}
  1. 创建认证控制器AuthController
java 复制代码
@RestController
@RequestMapping("/api/auth")
public class AuthController {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private JwtTokenProvider tokenProvider;

    @PostMapping("/signin")
    public ResponseEntity<?> authenticateUser(@RequestBody LoginRequest loginRequest) {
        Authentication authentication = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(
                        loginRequest.getUsername(),
                        loginRequest.getPassword()
                )
        );

        SecurityContextHolder.getContext().setAuthentication(authentication);
        String jwt = tokenProvider.generateToken(authentication);
        return ResponseEntity.ok(new JwtAuthenticationResponse(jwt));
    }
}

测试API

使用Postman或类似的工具测试以下端点:

  1. 登录POST /api/auth/signin
  2. 访问受保护资源GET /api/resource (需在Header中添加Authorization: Bearer <token>)

总结

本文通过Spring Boot和Spring Security结合JWT,实现了一个安全的RESTful API。开发者可以根据实际需求扩展功能,如角色权限管理、刷新令牌等。完整的代码示例可以在GitHub上找到。

参考资料

相关推荐
llwszx27 分钟前
深入理解Java锁原理(一):偏向锁的设计原理与性能优化
java·spring··偏向锁
云泽野1 小时前
【Java|集合类】list遍历的6种方式
java·python·list
二进制person2 小时前
Java SE--方法的使用
java·开发语言·算法
小阳拱白菜2 小时前
java异常学习
java
FrankYoou4 小时前
Jenkins 与 GitLab CI/CD 的核心对比
java·docker
麦兜*4 小时前
Spring Boot启动优化7板斧(延迟初始化、组件扫描精准打击、JVM参数调优):砍掉70%启动时间的魔鬼实践
java·jvm·spring boot·后端·spring·spring cloud·系统架构
KK溜了溜了4 小时前
JAVA-springboot 整合Redis
java·spring boot·redis
大只鹅4 小时前
解决 Spring Boot 对 Elasticsearch 字段没有小驼峰映射的问题
spring boot·后端·elasticsearch
天河归来4 小时前
使用idea创建springboot单体项目
java·spring boot·intellij-idea
weixin_478689765 小时前
十大排序算法汇总
java·算法·排序算法