以下是整合JWT到Spring Boot应用中的详细步骤:
1. 添加依赖
<dependencies>
<!-- Spring Boot Starter Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
</dependencies>
2. 配置Security
创建一个WebSecurityConfig类,继承WebSecurityConfigurerAdapter类,并配置JWT认证过滤器。
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/api/auth/**").permitAll()
.anyRequest().authenticated()
.and()
.addFilter(new JWTAuthenticationFilter(authenticationManager()));
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// Configure your authentication manager
// Here we use in-memory authentication for simplicity
auth.inMemoryAuthentication()
.withUser("user")
.password(new BCryptPasswordEncoder().encode("password"))
.roles("USER");
}
}
3. 创建JWT工具类
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
public class JWTUtil {
private static final String SECRET_KEY = "your_secret_key";
private static final long EXPIRATION_TIME = 864_000_000; // 10 days
public static String generateToken(String username) {
return Jwts.builder()
.setSubject(username)
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.signWith(SignatureAlgorithm.HS512, SECRET_KEY)
.compact();
}
public static boolean validateToken(String token) {
try {
Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token);
return true;
} catch (Exception e) {
return false;
}
}
public static String getUsernameFromToken(String token) {
Claims claims = Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();
return claims.getSubject();
}
}
4. 创建JWT认证过滤器
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class JWTAuthenticationFilter extends OncePerRequestFilter {
private AuthenticationManager authenticationManager;
public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain) throws ServletException, IOException {
String header = request.getHeader("Authorization");
if (header == null || !header.startsWith("Bearer ")) {
chain.doFilter(request, response);
return;
}
String token = header.replace("Bearer ", "");
if (JWTUtil.validateToken(token)) {
String username = JWTUtil.getUsernameFromToken(token);
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, null, new ArrayList<>());
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
chain.doFilter(request, response);
}
}
5. 创建认证Api
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/auth")
public class AuthController {
@Autowired
private AuthenticationManager authenticationManager;
@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody UserLoginDTO userLoginDTO) {
// 这里应该有一个服务层来处理用户认证的逻辑
// 为了示例,我们假设有一个AuthService服务
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
userLoginDTO.getUsername(),
userLoginDTO.getPassword()
)
);
SecurityContextHolder.getContext().setAuthentication(authentication);
String jwt = JWTUtil.generateToken(userLoginDTO.getUsername());
return ResponseEntity.ok().body(new JWTResponseDTO(jwt));
}
// 用户登录的DTO
public static class UserLoginDTO {
private String username;
private String password;
// getters and setters
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
// JWT响应的DTO
public static class JWTResponseDTO {
private String token;
public JWTResponseDTO(String token) {
this.token = token;
}
// getter
public String getToken() {
return token;
}
}
}