什么是JWT認(rèn)證
JWT認(rèn)證是一種輕量級(jí)的身份驗(yàn)證方法,它將用戶(hù)信息存儲(chǔ)在令牌中,而不是在服務(wù)器端的會(huì)話(huà)中。令牌是經(jīng)過(guò)數(shù)字簽名的,因此可以在客戶(hù)端和服務(wù)器之間安全地傳輸。JWT令牌包含了一些聲明(例如用戶(hù)名、角色等),這些聲明可以用于驗(yàn)證用戶(hù)的身份和授權(quán)。
集成JWT認(rèn)證的步驟
下面是集成JWT認(rèn)證的步驟:
添加依賴(lài)
創(chuàng)建JWT工具類(lèi)
配置JWT認(rèn)證
實(shí)現(xiàn)自定義用戶(hù)認(rèn)證
創(chuàng)建登錄接口
創(chuàng)建受保護(hù)的API接口
測(cè)試API接口
添加依賴(lài)
首先,在你的Spring Boot項(xiàng)目的pom.xml文件中添加以下依賴(lài):
<dependencies>
<!-- 其他依賴(lài) -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
</dependencies>創(chuàng)建JWT工具類(lèi)
接下來(lái),我們需要?jiǎng)?chuàng)建一個(gè)JWT工具類(lèi),用于生成和解析JWT令牌??梢詤⒖家韵麓a:
public class JwtUtils {
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) {
Date expirationDate = new Date(System.currentTimeMillis() + EXPIRATION_TIME);
return Jwts.builder()
.setSubject(username)
.setExpiration(expirationDate)
.signWith(SignatureAlgorithm.HS512, SECRET_KEY)
.compact();
}
public static String getUsernameFromToken(String token) {
Claims claims = Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody();
return claims.getSubject();
}
public static boolean validateToken(String token) {
try {
Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token);
return true;
} catch (SignatureException | MalformedJwtException | ExpiredJwtException | UnsupportedJwtException | IllegalArgumentException e) {
return false;
}
}
}配置JWT認(rèn)證
在Spring Boot應(yīng)用程序的配置類(lèi)中,需要添加一些配置來(lái)啟用JWT認(rèn)證??梢詤⒖家韵麓a:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/api/login").permitAll()
.anyRequest().authenticated()
.and()
.addFilter(new JwtAuthenticationFilter(authenticationManager()))
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
// 其他配置
}實(shí)現(xiàn)自定義用戶(hù)認(rèn)證
接下來(lái),我們需要實(shí)現(xiàn)自定義的用戶(hù)認(rèn)證邏輯??梢詣?chuàng)建一個(gè)實(shí)現(xiàn)UserDetailsService接口的類(lèi),并重寫(xiě)loadUserByUsername方法,根據(jù)用戶(hù)名查詢(xún)用戶(hù)信息??梢詤⒖家韵麓a:
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("User not found: " + username);
}
return new org.springframework.security.core.userdetails.User(
user.getUsername(),
user.getPassword(),
new ArrayList<>());
}
}創(chuàng)建登錄接口
現(xiàn)在,我們可以創(chuàng)建一個(gè)登錄接口,用于驗(yàn)證用戶(hù)并生成JWT令牌??梢詤⒖家韵麓a:
@RestController
@RequestMapping("/api")
public class AuthController {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private UserDetailsServiceImpl userDetailsService;
@PostMapping("/login")
public ResponseEntity<String> login(@RequestBody LoginRequest loginRequest) {
try {
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
loginRequest.getUsername(),
loginRequest.getPassword()));
} catch (BadCredentialsException e) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid credentials");
}
UserDetails userDetails = userDetailsService.loadUserByUsername(loginRequest.getUsername());
String token = JwtUtils.generateToken(userDetails.getUsername());
return ResponseEntity.ok(token);
}
}創(chuàng)建受保護(hù)的API接口
現(xiàn)在,我們可以創(chuàng)建一些受保護(hù)的API接口,只有經(jīng)過(guò)身份驗(yàn)證的用戶(hù)才能訪(fǎng)問(wèn)。可以參考以下代碼:
@RestController
@RequestMapping("/api")
public class UserController {
@GetMapping("/users")
public ResponseEntity<List<User>> getUsers() {
List<User> users = userRepository.findAll();
return ResponseEntity.ok(users);
}
}測(cè)試API接口
最后,可以使用Postman或其他HTTP客戶(hù)端工具來(lái)測(cè)試API接口。首先,發(fā)送POST請(qǐng)求到/login接口,傳遞用戶(hù)名和密碼作為請(qǐng)求體。服務(wù)器將返回生成的JWT令牌。然后,將該令牌添加到API請(qǐng)求的Authorization頭中,發(fā)送受保護(hù)的API請(qǐng)求。
總結(jié)
通過(guò)本文的介紹,我們了解了如何在Spring Boot應(yīng)用程序中集成JWT認(rèn)證。通過(guò)使用JWT令牌,我們可以實(shí)現(xiàn)基于令牌的身份驗(yàn)證和授權(quán),提高應(yīng)用程序的安全性。