使用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上找到。

参考资料

相关推荐
qq_336313939 分钟前
java基础-IO流(网络爬虫/工具包生成假数据)
java·爬虫·php
v***598312 分钟前
springBoot连接远程Redis连接失败(已解决)
spring boot·redis·后端
桦说编程30 分钟前
滑动窗口限流器的演进之路:从调度器实现到 Packed CAS
java·后端·性能优化
开开心心_Every1 小时前
安卓后台录像APP:息屏录存片段,行车用
java·服务器·前端·学习·eclipse·edge·powerpoint
初次攀爬者1 小时前
SpringBoot 整合 JWT + Redis 实现登录鉴权
java·redis·后端
悦悦妍妍1 小时前
spring-ioc
java
佛系打工仔1 小时前
绘制K线第一章:可见区间处理
java
wangkay882 小时前
【Java 转运营】Day02:抖音直播间流量底层逻辑全解析
java·新媒体运营
Coder_Boy_2 小时前
基于SpringAI的在线考试系统-企业级软件研发工程应用规范实现细节
大数据·开发语言·人工智能·spring boot