在spring boot中实现rest接口权限校验,最标准且灵活的做法是使用spring security结合自定义的`handlerinterceptor`或`methodinterceptor`。具体而言,可以通过定义一个拦截器,在请求到达controller之前解析http header中的token(如jwt),验证其合法性及用户权限,若校验失败则直接返回401或403状态码,从而实现对特定接口的访问控制。

如何配置Spring Security以启用全局安全过滤
要启用全局安全过滤,需要在项目中引入spring-boot-starter-security依赖,并创建一个继承自WebSecurityConfigurerAdapter的配置类(或在Spring Security 5.7+中使用SecurityFilterChain Bean)。在该配置中,可以指定哪些URL路径需要认证,哪些可以公开访问,并配置密码编码器。这样,所有进入DispatcherServlet的请求都会经过SecurityFilterChain的处理,为后续的细粒度权限控制打下基础。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeHttpRequests(authz -> authz
.requestMatchers("/api/public/**").permitAll()
.anyRequest().authenticated()
)
.httpBasic();
return http.build();
}
}上述代码配置了基本的HTTP Basic认证,并允许/api/public/下的路径无需认证即可访问,其他所有请求都需要认证。实际生产中通常会替换为JWT过滤器。
如何实现基于JWT的自定义Token校验逻辑
为了实现更灵活的权限校验,通常不直接使用Spring Security的表单或Basic认证,而是编写一个自定义的Filter或Interceptor来解析JWT。开发者需要在请求头中携带Token,校验逻辑包括验证签名是否有效、Token是否过期以及提取其中的用户信息。如果校验通过,则将用户信息存入ThreadLocal或SecurityContext供后续业务使用;如果失败,则抛出异常或返回错误响应。

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureException;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class JwtInterceptor implements HandlerInterceptor {
private static final String SECRET = "mySecretKey123456789";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("Authorization");
if (token == null || !token.startsWith("Bearer ")) {
response.setStatus(401);
response.getWriter().write("Missing or invalid token");
return false;
}
try {
Claims claims = Jwts.parser()
.setSigningKey(SECRET)
.parseClaimsJws(token.replace("Bearer ", ""))
.getBody();
// 将用户信息存入ThreadLocal或SecurityContext
request.setAttribute("userId", claims.getSubject());
return true;
} catch (SignatureException | IllegalArgumentException e) {
response.setStatus(401);
response.getWriter().write("Invalid token");
return false;
}
}
}该拦截器从Header中提取Bearer Token,使用预设密钥解析JWT。如果解析成功,说明Token有效,放行请求;否则返回401。注意在实际应用中,密钥应存储在配置文件中而非硬编码。
当Token中包含的角色信息与数据库不一致时如何处理
当Token中声明的角色(Role)与数据库中存储的最新角色不一致时,仅依赖Token进行权限判断会导致安全隐患。正确的做法是在权限校验阶段,不仅验证Token的有效性,还应根据Token中的用户ID查询数据库获取最新的角色列表,并与请求所需的权限进行比对。如果数据库中的角色已变更(例如被降级),即使Token未过期,也应拒绝访问。这要求权限校验逻辑具备实时性,不能仅做无状态的Token解析。


















