如何在不依赖JWT声明的情况下安全地从后端获取并验证用户角色

落雪酱_4432

落雪酱_4432

2026-05-07

614人浏览

原创

本文介绍一种安全可靠的方案:前端使用第三方oauth令牌(如google access token)完成身份认证后,后端验证其有效性并查询数据库中的用户角色,再签发一个由你完全控制的、含角色信息的自定义jwt;前端后续所有请求均携带该自定义jwt,确保角色数据不可篡改且服务端可信任。

本文介绍一种安全可靠的方案:前端使用第三方oauth令牌(如google access token)完成身份认证后,后端验证其有效性并查询数据库中的用户角色,再签发一个由你完全控制的、含角色信息的自定义jwt;前端后续所有请求均携带该自定义jwt,确保角色数据不可篡改且服务端可信任。

在基于第三方 OAuth(如 Google)的单页应用中,一个常见误区是直接将第三方 Access Token 用于前后端全部鉴权逻辑。但正如问题所述,Google 的 Access Token 不包含 roles 等业务级声明,且前端无法安全依赖后端响应中返回的角色字段——因为一旦攻击者拦截或篡改 /api/user/roles 接口的响应,就可能伪造高权限角色(如 "ROLE_ADMIN"),导致前端错误渲染管理界面,造成越权风险。

✅ 正确做法是:将第三方登录仅作为“身份断言”环节,真正的会话凭证(含角色)必须由你的后端签发、签名并全程管控。

✅ 推荐架构流程(安全闭环)

  1. 前端:用户点击“用 Google 登录” → 调用 Google OAuth 流程 → 获取 access_token(仅用于首次认证)

  2. 前端 → 后端:将该 access_token 发送到你自己的 /api/auth/login 接口(不暴露给资源服务器直接使用)

  3. 后端验证 & 角色注入:

    Boba
    Boba

    Boba是一款AI文本写作工具,AI动漫视频创作工具。

    下载
    • 使用 Google Public Keys(JWKS)验证 JWT 签名与有效期;
    • 解析 sub(用户唯一标识)或 email 查询本地数据库(如 users 表)获取该用户的角色列表(如 ["ROLE_USER", "ROLE_EDITOR"]);
    • 使用你自己的密钥(如 HS512 或 RS256)签发一个全新 JWT,明确嵌入 authorities(Spring Security 兼容格式):
      {
        "sub": "1234567890",
        "email": "user@example.com",
        "authorities": ["ROLE_USER", "ROLE_EDITOR"],
        "exp": 1735689600,
        "iat": 1735686000
      }
  4. 后端返回该自定义 JWT 给前端(建议通过 HttpOnly + Secure Cookie,或前端安全存储于内存/sessionStorage)

  5. 后续所有 API 请求:前端在 Authorization: Bearer 中携带该令牌

  6. 后端资源保护:配置 Spring Security 验证你自己的 JWT(而非 Google Token):

    @Configuration
    @EnableWebSecurity
    public class SecurityConfig {
        @Bean
        public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
            http
                .authorizeHttpRequests(auth -> auth
                    .requestMatchers("/api/public/**").permitAll()
                    .requestMatchers("/api/admin/**").hasRole("ADMIN")
                    .anyRequest().authenticated()
                )
                .oauth2ResourceServer(oauth2 -> oauth2
                    .jwt(jwt -> jwt
                        .jwtAuthenticationConverter(customJwtAuthConverter()) // 映射 authorities
                    )
                );
            return http.build();
        }
    
        @Bean
        public JwtAuthenticationConverter customJwtAuthConverter() {
            JwtGrantedAuthoritiesConverter authoritiesConverter = new JwtGrantedAuthoritiesConverter();
            authoritiesConverter.setAuthorityPrefix(""); // 不加 ROLE_ 前缀(若 payload 中已是 "ROLE_USER")
            authoritiesConverter.setAuthoritiesClaimName("authorities");
    
            JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
            converter.setJwtGrantedAuthoritiesConverter(authoritiesConverter);
            return converter;
        }
    }

⚠️ 关键注意事项

  • ❌ 切勿在前端解析或信任任意后端返回的“角色数组” —— 即使接口受保护,HTTP 响应仍可被浏览器插件或中间人篡改;
  • ✅ 所有权限判断必须在服务端完成:@PreAuthorize("hasRole('ADMIN')") 或 SecurityContext.getAuthentication().getAuthorities() 是唯一可信依据;
  • ? 自定义 JWT 必须使用强密钥签名(推荐 RS256 + 私钥签发 / 公钥校验),禁用 none 算法;
  • ? 前端角色展示(如菜单/按钮显隐)应仅作为 UX 优化,最终权限控制必须由后端 API 层强制校验;
  • ? 若需保留原始 Google Token(例如调用 Google Drive API),可将其作为额外 claim 存入自定义 JWT(如 "google_token": "ya29..."),但绝不用于你的系统鉴权。

通过该模式,你既复用了 Google 的身份认证能力,又完全掌控了授权上下文(roles)、会话生命周期与安全边界,真正实现“身份(Identity)与权限(Authority)分离”,兼顾安全性与可维护性。

相关专题

更多
python是前端还是后端
python是前端还是后端

Python属于前端也属于后端,其灵活性和丰富的生态系统使得开发人员能够在不同的领域中灵活运用。本专题为大家提供python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

2603

5

前端和后端的区别
前端和后端的区别

前端关注的是用户界面的设计和交互,而后端则注重数据处理和逻辑控制。想了解更多前端后端的相关内容,可以阅读本专题下面的文章。

2024.03.19

6630

13

后端的主要工作内容介绍
后端的主要工作内容介绍

后端是应用程序的服务端部分,负责核心任务,如数据库交互、业务逻辑处理和响应客户端请求。想了解更多后端的相关内容,可以阅读本专题下面的文章。

2024.03.19

6066

10

js获取数组长度的方法
js获取数组长度的方法

在js中,可以利用array对象的length属性来获取数组长度,该属性可设置或返回数组中元素的数目,只需要使用“array.length”语句即可返回表示数组对象的元素个数的数值,也就是长度值。php中文网还提供JavaScript数组的相关下载、相关课程等内容,供大家免费下载使用。

2023.06.20

5126

5

js刷新当前页面
js刷新当前页面

js刷新当前页面的方法:1、reload方法,该方法强迫浏览器刷新当前页面,语法为“location.reload([bForceGet]) ”;2、replace方法,该方法通过指定URL替换当前缓存在历史里(客户端)的项目,因此当使用replace方法之后,不能通过“前进”和“后退”来访问已经被替换的URL,语法为“location.replace(URL) ”。php中文网为大家带来了js刷新当前页面的相关知识、以及相关文章等内容

2023.07.04

1249

3

js四舍五入
js四舍五入

js四舍五入的方法:1、tofixed方法,可把 Number 四舍五入为指定小数位数的数字;2、round() 方法,可把一个数字舍入为最接近的整数。php中文网为大家带来了js四舍五入的相关知识、以及相关文章等内容

2023.07.04

5044

6

js删除节点的方法
js删除节点的方法

js删除节点的方法有:1、removeChild()方法,用于从父节点中移除指定的子节点,它需要两个参数,第一个参数是要删除的子节点,第二个参数是父节点;2、parentNode.removeChild()方法,可以直接通过父节点调用来删除子节点;3、remove()方法,可以直接删除节点,而无需指定父节点;4、innerHTML属性,用于删除节点的内容。

2023.09.01

980

4

JavaScript转义字符
JavaScript转义字符

JavaScript中的转义字符是反斜杠和引号,可以在字符串中表示特殊字符或改变字符的含义。本专题为大家提供转义字符相关的文章、下载、课程内容,供大家免费下载体验。

2023.09.04

1916

5

js生成随机数的方法
js生成随机数的方法

js生成随机数的方法有:1、使用random函数生成0-1之间的随机数;2、使用random函数和特定范围来生成随机整数;3、使用random函数和round函数生成0-99之间的随机整数;4、使用random函数和其他函数生成更复杂的随机数;5、使用random函数和其他函数生成范围内的随机小数;6、使用random函数和其他函数生成范围内的随机整数或小数。

2023.09.04

3605

4

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
LLVM官方文档
LLVM官方文档

共0课时 | 0人学习