Pinpoint Basic Login 模块详解:JWT Cookie 认证的启用与配置指南
【免费下载链接】pinpointAPM, (Application Performance Management) tool for large-scale distributed systems.项目地址: https://gitcode.com/gh_mirrors/pi/pinpoint
导读
Pinpoint 是一个面向大规模分布式系统的 APM(应用性能监控)工具,其 Web 控制台默认没有启用认证。basic-login模块为 Pinpoint Web 提供了基于 Spring Security 的「账号密码 + JWT Cookie」登录认证能力,通过一个启动参数即可开启。本文基于仓库中 basic-login/README.md 与该模块源码,完整讲解启用方法、账号配置、JWT Cookie 安全属性调优(HttpOnly / Secure / SameSite)、HTTPS 部署下的注意事项,以及模块内部的认证调用链与配置校验逻辑,帮助你在生产环境中安全地保护 Pinpoint Web 控制台。
一、模块定位与启用方式
pinpoint-basic-login是 Pinpoint 仓库中的一个独立 Maven 模块(见 basic-login/pom.xml),以 jar 形式被 Web 应用引入。它本身不参与 Agent 采集链路,只负责 Web 控制台的登录认证,属于可插拔的「登录模块」。
启用方式是在启动 Pinpoint Web 时通过 JVM 系统属性指定登录模块类型:
-Dpinpoint.modules.web.login=basicLogin对应的源码开关位于 PinpointBasicLoginConfig.java:该类使用@ConditionalOnProperty(name = "pinpoint.modules.web.login", havingValue = "basicLogin")条件装配,只有当该属性值精确等于basicLogin时,Spring Security 的整套配置才会生效。也就是说,不传该参数时模块完全不加载,Web 行为与未集成登录时一致。
注意:
pinpoint.modules.web.login支持的值与 Web 模块支持的登录模块列表有关,basicLogin是其中一种实现;本文仅围绕该值对应的 basic-login 模块展开。
二、账号与角色配置
2.1 用户与管理员账号
账号通过pinpoint-web.properties(即 Web 应用的配置覆盖文件,仓库中的默认样例位于 web/src/main/resources/pinpoint-web-root.properties)中的两个属性声明:
# 普通用户:可用除 Admin REST API 外的全部功能 web.security.auth.user=alice:foo,bob:bar # 管理员:可用全部功能(包括 /api/admin/**) web.security.auth.admin=eve:baz- 格式为
用户名:密码,多个账号用英文逗号分隔; - 密码以明文写在配置文件中,由模块在加载时使用 BCrypt 加密(
BCryptPasswordEncoder,见 PinpointBasicLoginConfig.java); - 解析逻辑在 BasicLoginProperties.java:按
:切分用户名:密码,切分后恰好为两段才会被注册,否则静默忽略。
2.2 角色与路径授权
模块区分两类角色:
ROLE_USER:普通用户,可访问除 Admin API 外的全部功能;ROLE_ADMIN:管理员,额外拥有/api/admin/**的访问权限。
授权规则定义在 PinpointBasicLoginConfig.java 的SecurityFilterChain中:
http.authorizeHttpRequests(customizer -> { customizer.requestMatchers("/api/admin/**").hasRole("ADMIN"); }); // ... http.authorizeHttpRequests(customizer -> { customizer .requestMatchers("/api-public/**").permitAll() .requestMatchers("/api-ext-auth/**").permitAll() .anyRequest().authenticated(); });即:/api/admin/**需要ADMIN角色;/api-public/**与/api-ext-auth/**匿名可访问(permitAll);其余所有请求必须认证(anyRequest().authenticated())。无权限访问 Admin API 时会被重定向到 BasicLoginConstants.java 中定义的URI_NOT_AUTHORIZED = "/not_authorized.html"。
三、JWT Cookie 安全属性配置
登录成功后,模块生成pinpointJwtCookie(Cookie 名称定义在 BasicLoginConstants.java),后续请求靠该 Cookie 完成无状态认证。
3.1 三个可调属性与默认值
| 配置项(pinpoint-web.properties) | 环境变量(Docker / Kubernetes) | 默认值 | 说明 |
|---|---|---|---|
web.security.auth.jwt.cookie.http-only | WEB_SECURITY_AUTH_JWT_COOKIE_HTTP_ONLY | true | 禁止 JavaScript 读取 Cookie,降低 XSS 窃取风险 |
web.security.auth.jwt.cookie.secure | WEB_SECURITY_AUTH_JWT_COOKIE_SECURE | false | 仅通过 HTTPS 传输;Web 走 HTTPS 时应设为true |
web.security.auth.jwt.cookie.same-site | WEB_SECURITY_AUTH_JWT_COOKIE_SAME_SITE | Lax | 跨站请求携带 Cookie 的策略,可设为Lax/Strict/None等 |
属性默认值在 BasicLoginProperties.java 中以 Spring@Value注解声明:
@Value("${web.security.auth.jwt.cookie.http-only:true}") private boolean jwtCookieHttpOnly; @Value("${web.security.auth.jwt.cookie.secure:false}") private boolean jwtCookieSecure; @Value("${web.security.auth.jwt.cookie.same-site:Lax}") private String jwtCookieSameSite;3.2 Cookie 如何被构造
Cookie 的构造逻辑在 BasicLoginService.createNewCookie():
Path=/:全站生效;HttpOnly:按jwtCookieHttpOnly设置,默认开启;Secure:按jwtCookieSecure设置,默认关闭;SameSite:仅当值非空且非空白时才写入 Cookie 属性;MaxAge:等于 JWT 的过期时长(见下文),单位为秒。
createNewCookie()被登录成功处理器 SaveJwtTokenAuthenticationSuccessHandler.java 调用:认证成功后生成 Cookie 写入响应、设置 HTTP 200 与 JSON Content-Type,并重定向到主页面/。
3.3 配置示例
普通 HTTP 内网部署(推荐保持默认即可):
web.security.auth.jwt.cookie.http-only=true web.security.auth.jwt.cookie.secure=false web.security.auth.jwt.cookie.same-site=LaxHTTPS 公网部署(必须开启 Secure):
web.security.auth.jwt.cookie.http-only=true web.security.auth.jwt.cookie.secure=true web.security.auth.jwt.cookie.same-site=LaxDocker / Kubernetes 环境下使用环境变量注入:
WEB_SECURITY_AUTH_JWT_COOKIE_HTTP_ONLY=true WEB_SECURITY_AUTH_JWT_COOKIE_SECURE=true WEB_SECURITY_AUTH_JWT_COOKIE_SAME_SITE=Lax安全提示:若将
same-site设为None,浏览器强制要求 Cookie 同时带有Secure属性(即必须走 HTTPS),否则 Cookie 会被拒绝,实际部署时请按协议约束配置。
四、JWT 密钥配置(必填项)
启用 basicLogin 后,必须配置 JWT 签名密钥,否则 Web 启动失败:
web.security.auth.jwt.secretkey=<generate-a-random-secret>对应源码中的强制校验位于 BasicLoginProperties.afterPropertiesSet(),启动时检查两件事:
- 密钥非空——错误信息提示:请在
pinpoint-web.properties中设置一个至少 24 个字符的随机字符串; - 密钥不得等于
__PINPOINT_JWT_SECRET__——该值曾作为示例值随 4.0.0 之前的版本发布,属于公开已知的泄露密钥,源码注释明确要求必须更换。
对应单元测试 BasicLoginServiceTest.leakedSecretKeyShouldFailStartup() 验证了使用该泄露密钥时容器启动会抛出包含publicly known的IllegalArgumentException。
生成随机密钥的参考命令(任选其一):
# Linux / macOS openssl rand -base64 32 # 或 head -c 32 /dev/urandom | base64五、认证流程与实现原理
5.1 登录链路
- 用户访问 Web 任意受保护路径,被重定向到
/login(URI_LOGIN,见 BasicLoginConstants.java); - 表单登录(
formLogin)校验账号密码,密码由BCryptPasswordEncoder校验; - 认证成功后 SaveJwtTokenAuthenticationSuccessHandler 生成 JWT 并写入
pinpointJwtCookie,随后重定向回/; - 后续每次请求由 JwtRequestFilter 从 Cookie 中解析 JWT,验证通过后把用户信息写入
SecurityContext,实现无状态认证。
5.2 JWT 的结构与过期时间
JwtService.java 负责 Token 的签发与解析:
- Claims:包含
userId与userRole(角色列表); - 签发时间:
issuedAt为当前时间; - 过期时间:
expiration为「当前时间 + 过期时长」; - 默认过期时长:
DEFAULT_EXPIRATION_TIME_SECONDS = TimeUnit.HOURS.toSeconds(12),即12 小时,定义于 BasicLoginProperties.java; - 签名算法:使用密钥通过
Keys.hmacShaKeyFor()构造 HMAC-SHA 密钥(对应 jjwt 库),密钥先经 Base64 编码后参与构造; - 校验:解析时使用
JwtParser.verifyWith(secretKey)验签。
5.3 无状态会话与退出
安全配置同时声明了 PinpointBasicLoginConfig.configure() 中的以下行为:
- 无状态会话:
SessionCreationPolicy.STATELESS,不创建服务端 Session,认证完全依赖 Cookie 中的 JWT; - 禁用 CSRF 与 HTTP Basic:
csrf.disable()与httpBasic.disable(); - 退出登录:登出时删除
pinpointJwtCookie(logout.deleteCookies("pinpointJwt")); - 预认证检查:
PreAuthenticationCheckFilter在登录页请求到来前检查是否已认证,若已登录访问/login则直接重定向回/,避免重复登录。
5.4 用户存储
用户保存在内存中:PinpointMemoryUserDetailsService 将普通用户与管理员合并进一个Map<String, UserDetails>(管理员覆盖同名普通用户),并通过Map.copyOf固化。loadUserByUsername()每次返回 User 对象的凭证副本,单元测试 验证了即使外部对返回对象调用eraseCredentials()清空密码,也不会影响内存中的原始凭证。用户名不存在时抛出UsernameNotFoundException("User not found: " + username)。
六、异常处理与容错
JwtRequestFilter 与 BasicLoginService.getUserDetails() 对以下异常情况做了容错处理(均记录 warn 日志后放行请求,交由安全框架判定为未认证):
- Cookie 缺失或为空:直接放行;
- Token 过期:捕获
ExpiredJwtException,日志提示This token already expired.; - Token 非法(非 JWT 格式或验签失败):捕获
JwtException,日志提示Invalid JWT token.; - 用户不存在:捕获
UsernameNotFoundException,日志提示Could not find user for JWT token.。
这些行为均有对应的单元测试覆盖:BasicLoginServiceTest.java 分别验证了「用户不存在时忽略 JWT」「非法 JWT 被忽略」「空 JWT 被忽略」。
七、典型部署场景总结
| 场景 | 推荐配置 |
|---|---|
| 内网 HTTP 直连 | 保持默认:http-only=true、secure=false、same-site=Lax |
| HTTPS 反向代理 / 公网部署 | 追加web.security.auth.jwt.cookie.secure=true(环境变量为WEB_SECURITY_AUTH_JWT_COOKIE_SECURE=true) |
| 跨站集成(如嵌入第三方页面) | 谨慎使用same-site=None,且必须同时开启secure=true并保证 HTTPS |
| 任何场景 | 必须设置 ≥24 字符的随机web.security.auth.jwt.secretkey,禁止使用__PINPOINT_JWT_SECRET__ |
启用口令为-Dpinpoint.modules.web.login=basicLogin,配合 pinpoint-web-root.properties 中注释示例的账号、密钥与 Cookie 三项配置,即可为 Pinpoint Web 控制台开启一套安全、无状态的 JWT Cookie 登录认证方案。更深层的实现细节可继续阅读 basic-login 模块源码与测试用例 BasicLoginServiceTest.java。
【免费下载链接】pinpointAPM, (Application Performance Management) tool for large-scale distributed systems.项目地址: https://gitcode.com/gh_mirrors/pi/pinpoint
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考