You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Security授权时403错误:无效Base64编码字符串求助

问题描述

搭建Spring Security认证授权体系后,认证功能正常可获取JWT令牌(当前用户角色为ROLE_USER),但调用GET /api/users接口时返回403 Forbidden错误,错误信息:

{"error_token": "The input is not a valid base 64 encoded string"}

问题原因

1. JWT角色序列化与反序列化不匹配

  • 认证过滤器(CustomAuthentificationFilter)生成JWT时,用Collectors.joining()将用户角色集合拼接成单个字符串(例如单角色时存储为"ROLE_USER",多角色时为"ROLE_ADMIN,ROLE_USER")。
  • 授权过滤器(CustomAuthorizationFilter)解析JWT时,尝试用decodedJWT.getClaim("roles").asArray(String.class)将角色解析为字符串数组。但JWT中实际存储的是单个字符串,JWT库会尝试将该字符串当作base64编码的数组内容解码,最终抛出"不是有效的base64编码字符串"的错误。

2. 授权过滤器逻辑错误

filterChain.doFilter(request, response)被放在遍历角色的forEach循环内部,会导致过滤器链被多次执行,引发异常。

3. 安全配置角色校验规则错误

hasAnyRole方法会自动给角色前缀添加ROLE_,但配置中传入的参数是"ROLE_ADMIN","ROLE_USER",最终会变成匹配ROLE_ROLE_ADMIN和ROLE_ROLE_USER,导致角色校验失败。

解决步骤

1. 修复JWT角色序列化方式(认证过滤器)

将角色集合序列化为字符串数组,替换原有的拼接逻辑:
修改CustomAuthentificationFilter中生成access_token和refresh_token的withClaim代码:

// 原代码
.withClaim("roles", user.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.joining()))
// 修改为
.withClaim("roles", user.getAuthorities().stream().map(GrantedAuthority::getAuthority).toArray(String[]::new))

2. 修复授权过滤器逻辑

将filterChain.doFilter(request, response)移出角色遍历循环,确保过滤器链仅执行一次:
修改CustomAuthorizationFilter核心逻辑:

try {
    String token = authorizationHeader.substring("Bearer ".length());
    Algorithm algorithm = Algorithm.HMAC256("secret".getBytes());
    JWTVerifier jwtVerifier = JWT.require(algorithm).build();
    DecodedJWT decodedJWT = jwtVerifier.verify(token);
    String username = decodedJWT.getSubject();
    String[] roles = decodedJWT.getClaim("roles").asArray(String.class);
    Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
    
    // 遍历收集角色
    stream(roles).forEach(role -> {
        authorities.add(new SimpleGrantedAuthority(role));
    });
    
    // 初始化认证信息并执行过滤器链(移出循环)
    UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, null, authorities);
    SecurityContextHolder.getContext().setAuthentication(authenticationToken);
    filterChain.doFilter(request, response);
} catch (Exception exception) {
    log.error("error loggin in: {}", exception.getMessage());
    response.setHeader("error", exception.getMessage());
    response.setStatus(FORBIDDEN.value());
    Map<String, String> error = new HashMap<>();
    error.put("error_token", exception.getMessage());
    response.setContentType(APPLICATION_JSON_VALUE);
    new ObjectMapper().writeValue(response.getOutputStream(), error);
}

3. 修复安全配置角色校验规则

针对hasAnyRole的自动前缀特性,修改授权规则的角色参数:

// 原代码
http.authorizeRequests().antMatchers("/api/users").hasAnyRole("ROLE_ADMIN","ROLE_USER");
// 修改为(自动添加ROLE_前缀)
http.authorizeRequests().antMatchers("/api/users").hasAnyRole("ADMIN","USER");
// 或改用hasAnyAuthority(直接使用完整角色名,不自动加前缀)
// http.authorizeRequests().antMatchers("/api/users").hasAnyAuthority("ROLE_ADMIN","ROLE_USER");

内容的提问来源于stack exchange,提问作者user13906062

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 05:45:36