下面是关于“Spring Boot集成JWT实现前后端认证的示例代码”的完整攻略。
1. 什么是JWT
JWT全称为JSON Web Token,是一种基于JSON的轻量级标准,我们可以使用JWT实现前后端的认证功能。其中,JWT由三部分组成:Header、Payload、Signature。Header和Payload分别是一个JSON对象(字典),而Signature则是对Header、Payload加密后的结果。
2. 如何集成JWT
为了集成JWT,你需要做以下几个步骤:
2.1 添加依赖
你需要在pom.xml文件中添加以下依赖:
<!-- JWT依赖 -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.10.7</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.10.7</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.10.7</version>
<scope>runtime</scope>
</dependency>
2.2 实现JWT工具类
接下来,你需要实现一个工具类,用于生成JWT Token和解析JWT Token。参考代码如下:
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@Component
public class JwtTokenUtil {
private static final String CLAIM_KEY_USERNAME = "sub";
private static final String CLAIM_KEY_CREATED = "created";
@Value("${jwt.secret}")
private String secret;
@Value("${jwt.expiration}")
private Long expiration;
/**
* 根据用户信息生成Token
* @param username 用户名
* @return
*/
public String generateToken(String username) {
Map<String, Object> claims = new HashMap<>();
claims.put(CLAIM_KEY_USERNAME, username);
claims.put(CLAIM_KEY_CREATED, new Date());
return Jwts.builder()
.setClaims(claims)
.setExpiration(generateExpirationDate())
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
/**
* 解析Token,获取用户信息
* @param token
* @return
*/
public String getUsernameFromToken(String token) {
String username;
try {
Claims claims = getClaimsFromToken(token);
username = claims.getSubject();
} catch (Exception e) {
username = null;
}
return username;
}
/**
* 验证Token是否有效
* @param token
* @param username
* @return
*/
public boolean validateToken(String token, String username) {
String usernameFromToken = getUsernameFromToken(token);
return usernameFromToken.equals(username) && !isTokenExpired(token);
}
/**
* 判断Token是否已过期
* @param token
* @return
*/
private boolean isTokenExpired(String token) {
Date expirationDate = getExpirationDateFromToken(token);
return expirationDate.before(new Date());
}
/**
* 从Token中获取过期时间
* @param token
* @return
*/
private Date getExpirationDateFromToken(String token) {
Claims claims = getClaimsFromToken(token);
return claims.getExpiration();
}
/**
* 根据Token获取Claims信息
* @param token
* @return
*/
private Claims getClaimsFromToken(String token) {
Claims claims;
try {
claims = Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
} catch (Exception e) {
claims = null;
}
return claims;
}
/**
* 根据Token生成过期时间
* @return
*/
private Date generateExpirationDate() {
return new Date(System.currentTimeMillis() + expiration * 1000);
}
}
这里我们使用了@Component注解将JwtTokenUtil类标记为Spring组件,以便在其他组件中自动注入该类的实例。需要注意的是,你需要在application.properties文件中配置jwt.secret和jwt.expiration两个参数。
2.3 实现认证接口
你需要实现一个认证接口,用于用户登录。该接口将会根据用户名和密码生成对应的JWT Token,并返回给前端。
import com.example.demo.util.JwtTokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/auth")
public class AuthController {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Autowired
private PasswordEncoder passwordEncoder;
/**
* 用户登录认证
* @param authenticationRequest
* @return
*/
@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody AuthenticationRequest authenticationRequest) {
String username = authenticationRequest.getUsername();
String password = authenticationRequest.getPassword();
Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
String token = jwtTokenUtil.generateToken(username);
return ResponseEntity.ok(new AuthenticationResponse(token));
}
}
这里我们使用@RestController注解将AuthController类标记为Spring MVC的控制器,并使用@RequestMapping注解指定了该Controller的基础路由,即/auth。需要注意的是,这里我们还使用了@Autowired注解将AuthenticationManager、UserDetailsService、JwtTokenUtil、PasswordEncoder四个类自动注入到AuthController类中,以便我们可以直接使用它们的实例。
2.4 实现JWT过滤器
你需要实现一个JWT过滤器,用于在请求中验证JWT Token的合法性并鉴权。参考代码如下:
import com.example.demo.util.JwtTokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
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;
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private JwtTokenUtil jwtTokenUtil;
/**
* JWT过滤器逻辑
* @param request
* @param response
* @param filterChain
* @throws ServletException
* @throws IOException
*/
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String authHeader = request.getHeader("Authorization");
if (authHeader != null && authHeader.startsWith("Bearer ")) {
String authToken = authHeader.substring("Bearer ".length());
String username = jwtTokenUtil.getUsernameFromToken(authToken);
if (username != null && jwtTokenUtil.validateToken(authToken, username)) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
} else {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.getWriter().write("Token invalid or expired!");
return;
}
}
filterChain.doFilter(request, response);
}
}
这里我们使用了@Component注解将JwtAuthenticationTokenFilter类标记为Spring组件,以便在其他组件中自动注入该类的实例。
2.5 配置Spring Security
最后,你需要为Spring Security添加以下配置:
import com.example.demo.filter.JwtAuthenticationTokenFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsServiceImpl userDetailsService;
@Autowired
private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService);
provider.setPasswordEncoder(passwordEncoder());
return provider;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers("/auth/**").permitAll()
.anyRequest().authenticated()
.and()
.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
这里我们使用了@Configuration、@EnableWebSecurity、@EnableGlobalMethodSecurity注解将SecurityConfig类标记为Spring Security的配置类,并使用了@Bean注解将PasswordEncoder、DaoAuthenticationProvider、AuthenticationManager三个组件标记为Spring组件,以便在其他组件中自动注入它们的实例。
3. 示例说明
下面是两个例子,以说明如何使用本文中的代码实现前后端的认证功能。
3.1 登录认证
前端发送POST请求到http://localhost:8080/auth/login,请求体包含用户名和密码,后端返回JWT Token。参考代码如下:
$.ajax({
type: "POST",
url: "/auth/login",
data: JSON.stringify({
"username": "username",
"password": "password"
}),
dataType: "json",
contentType: "application/json",
success: function (response) {
var token = response.token;
},
error: function (response) {
// 处理错误
}
})
3.2 请求鉴权
前端发送带有JWT Token的请求到后端,后端通过JWT过滤器对Token进行验证,并进行鉴权。参考代码如下:
$.ajax({
type: "GET",
url: "/api",
headers: {
"Authorization": "Bearer " + token
},
success: function (response) {
// 处理响应
},
error: function (response) {
// 处理错误
}
})
4. 结语
通过本文的讲解,你已经了解了如何集成JWT来实现前后端的认证功能,并且实现了一个完整的示例代码。需要注意的是,本文代码的示例只是一种可能的实现方式,你可以根据你的实际需求和技术背景进行优化和改进。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring Boot 集成JWT实现前后端认证的示例代码 - Python技术站