什么是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)用程序的安全性。