下面是“SpringBoot+Spring Security+JWT实现RESTful Api权限控制的方法”的完整攻略:
简介
本篇攻略介绍如何使用SpringBoot、Spring Security、JWT实现RESTful Api权限控制。Spring Security可以提供强大的身份验证和授权功能,而JWT可以用于生成安全的令牌。本攻略将介绍如何将这两个框架结合使用,以便在RESTful Api应用程序中实现身份验证和访问控制功能。
环境和依赖
本文使用的环境和依赖如下:
环境:
- JDK 1.8 或以上
- SpringBoot 2.5.x
- Spring Security 5.5.x
依赖:
<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>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>7.0.1.Final</version>
</dependency>
</dependencies>
代码实现
配置Spring Security
首先,我们需要配置Spring Security,以便在应用程序中启用安全性。我们需要创建一个SecurityConfig类,该类将扩展WebSecurityConfigurerAdapter类,并覆盖configure方法,以配置Spring Security。
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserService userService;
@Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
@Autowired
private JwtAuthenticationFilter jwtAuthenticationFilter;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/api/auth/**").permitAll()
.anyRequest().authenticated()
.and().exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
}
}
在该类中,我们定义了PasswordEncoder,该类用于对密码进行加密。我们还覆盖了configure方法,并使用UserService和PasswordEncoder配置了身份验证。最后,我们定义了HttpSecurity对象,以便在应用程序中启用授权。我们定义了url映射,任何未经授权的请求都将被阻挡,并向用户返回403错误。我们为所有的请求配置了JwtAuthenticationFilter,以确保它们都被验证。
创建JwtToken工具
接下来,我们需要创建JwtToken工具类,该类将被用于生成和解析jwt token。这里我们使用jjwt库实现JwtToken。
@Component
public class JwtTokenUtil {
private static final String SECRET_KEY = "my-secret-key";
private static final SignatureAlgorithm SIGNATURE_ALGORITHM = SignatureAlgorithm.HS512;
@Value("${jwt.tokenExpirationTime}")
private Long tokenExpirationTime;
public String generateToken(UserDetails userDetails) {
Date now = new Date();
Date expiryDate = new Date(now.getTime() + tokenExpirationTime);
return Jwts.builder().setSubject(userDetails.getUsername())
.setIssuedAt(now)
.setExpiration(expiryDate)
.signWith(SIGNATURE_ALGORITHM, SECRET_KEY)
.compact();
}
public String getUsernameFromToken(String token) {
return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody().getSubject();
}
public boolean validateToken(String token, UserDetails userDetails) {
final String username = getUsernameFromToken(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}
private boolean isTokenExpired(String token) {
final Date expiration = getExpirationDateFromToken(token);
return expiration.before(new Date());
}
private Date getExpirationDateFromToken(String token) {
return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody().getExpiration();
}
}
在该类中,我们使用了@Value注解来获取配置文件中的tokenExpirationTime属性。然后,我们定义了generateToken方法,该方法根据传入的用户细节生成jwt token。我们还定义了getUsernameFromToken方法,该方法从jwt token中获取用户名。最后,我们定义了validateToken方法,该方法用于验证jwt token是否有效。
创建JwtAuthenticationFilter类
接下来,我们需要创建一个JwtAuthenticationFilter类,该类将被用于解析jwt token,并使用Spring Security进行身份验证。该类将继承OncePerRequestFilter类,并覆盖doFilterInternal方法。
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
final String requestHeader = request.getHeader("Authorization");
String username = null;
String jwtToken = null;
if (requestHeader != null && requestHeader.startsWith("Bearer ")) {
jwtToken = requestHeader.substring(7);
username = jwtTokenUtil.getUsernameFromToken(jwtToken);
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (jwtTokenUtil.validateToken(jwtToken, userDetails)) {
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
}
filterChain.doFilter(request, response);
}
}
在该类中,我们首先检查HTTP请求头中是否存在Authorization头,并分离出Bearer token。然后,我们使用JwtTokenUtil获取用户的用户名,并尝试使用它来找到用户的详细信息。最后,我们使用JwtTokenUtil验证jwt token是否有效,并使用UsernamePasswordAuthenticationToken设置用户的详细信息。
创建JwtAuthenticationEntryPoint类
我们还需要创建一个JwtAuthenticationEntryPoint类,该类将被用于处理身份验证错误,以确保所有未经验证的用户都被拦截。
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
}
在该类中,我们覆盖了commence方法,该方法用于处理身份验证错误。我们向用户返回HTTP 401错误。
创建UserService类
我们还需要创建一个UserService类,该类将为Spring Security获取用户详细信息。
@Service
public class UserService 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(username);
}
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(),
new ArrayList<>());
}
}
在该类中,我们实现了UserDetailsService,并覆盖了loadUserByUsername方法,该方法用于从数据库中获取用户详细信息。
创建RestController类
最后,我们还需要创建一个RestController类,该类包含需要进行身份验证的RESTful API。
@RestController
@RequestMapping("/api")
public class MainController {
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Autowired
private UserService userService;
@PostMapping("/auth/login")
public ResponseEntity<?> authenticateUser(@RequestBody LoginRequest loginRequest) {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()));
SecurityContextHolder.getContext().setAuthentication(authentication);
String jwtToken = jwtTokenUtil.generateToken(userService.loadUserByUsername(loginRequest.getUsername()));
return ResponseEntity.ok(new JwtAuthenticationResponse(jwtToken));
}
@GetMapping("/user")
public ResponseEntity<?> getUser(HttpServletRequest request) {
String jwtToken = request.getHeader("Authorization").substring(7);
return ResponseEntity.ok(jwtTokenUtil.getUsernameFromToken(jwtToken));
}
}
在该类中,我们为登录API定义了一个POST 映射(/api/auth/login),该映射将处理登录请求。我们还为获取用户API定义了一个GET映射(/api/user),该映射将返回当前已登录用户的用户名。
示例
登录API
我们可以使用curl命令或Postman软件来测试登录API,请求的body数据为:
{
"username": "user",
"password": "password"
}
$ curl -X POST -H "Content-Type: application/json" \
-d '{"username": "user", "password": "password"}' \
http://localhost:8080/api/auth/login
请求成功后,响应内容如下:
{
"accessToken": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ1c2VyIiwiZXhwIjoxNjIzNDk5NjM0LCJpYXQiOjE2MjM0NzM2MzR9.u6FGd1fxn6e9zGNNSmNirLfqD9r8kHLB_crziwZO6Zj0WfOsA5SHytUdGU-FL7E7dqqGbDQgK5iK0suEZcVUwA"
}
获取用户API
我们可以使用curl命令或Postman软件来测试获取用户API,请求的Header中需要包含刚刚获取到的accessToken,示例如下:
$ curl -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ1c2VyIiwiZXhwIjoxNjIzNDk5NjM0LCJpYXQiOjE2MjM0NzM2MzR9.u6FGd1fxn6e9zGNNSmNirLfqD9r8kHLB_crziwZO6Zj0WfOsA5SHytUdGU-FL7E7dqqGbDQgK5iK0suEZcVUwA" \
http://localhost:8080/api/user
请求成功后,响应内容如下:
"user"
结束语
本篇攻略中介绍了如何使用SpringBoot、Spring Security、JWT实现RESTful Api权限控制,包括配置Spring Security,创建JwtToken工具类,创建JwtAuthenticationFilter类,创建JwtAuthenticationEntryPoint类,创建UserService类,创建RestController类,并提供了两个示例。希望这篇攻略能够帮助你实现RESTful API的权限控制。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:SpringBoot+Spring Security+JWT实现RESTful Api权限控制的方法 - Python技术站