Class HttpServletAuthService
- All Implemented Interfaces:
AuthService
- Direct Known Subclasses:
DefaultAuthService
实现了AuthService接口,提供了基于HTTP Servlet的认证服务基础实现
主要功能: 1. 从HTTP请求中获取Token(支持Header、Cookie、Parameter多种方式) 2. 用户登录/登出(通过Cookie管理Token) 3. Token刷新机制(自动使用Refresh Token刷新Access Token) 4. URL认证检查(支持白名单配置)
Token获取优先级:
1. Cookie中的Token
2. Authorization Header
3. 自定义Header
4. 请求参数(H10:默认禁用,防 Token 泄露进浏览器历史/访问日志/Referer;需要时子类覆写
allowQueryToken() 返回 true 或通过配置 nif.auth.allow-query-token 开启)
子类需要实现的抽象方法: - getRequest(): 获取HttpServletRequest - getResponse(): 获取HttpServletResponse - userDetailService(): 获取UserDetailService实例 - jwtEncoder(): 获取JWTEncoder实例 - jwtDecoder(): 获取JWTDecoder实例
- Author:
- Kerbores(kerbores@riemann.tech)
-
Field Summary
Fields -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionvoid添加Cookieprotected boolean是否允许从 URL 查询参数中获取 Token(H10)booleanauthentication(List<String> withoutAuthenticationUrlRegulars) URL认证检查获取认证Header的Key获取Cookie配置abstract jakarta.servlet.http.HttpServletRequest获取HttpServletRequest对象abstract jakarta.servlet.http.HttpServletResponse获取HttpServletResponse对象abstract JWTDecoder获取JWT解码器abstract JWTEncoder获取JWT编码器用户登录voidlogout()用户登出尝试获取当前认证用户boolean检查URL是否匹配白名单路径模式获取当前用户的刷新令牌(Refresh Token)refreshToken(String subject) 为指定用户生成刷新令牌获取Refresh Token的键名booleanskip()是否跳过认证检查subject()获取当前会话的Subject(主题)token()获取当前用户的访问令牌(Token)为指定用户生成访问令牌tokenKey()获取Token的键名获取有效的Token(优先Access Token,否则使用Refresh Token)tryRefreshToken(String refreshToken) 尝试使用Refresh Token刷新Access Tokenuser()获取当前登录用户abstract UserDetailService获取用户详情服务Methods inherited from class Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, waitMethods inherited from interface AuthService
permissions, roles, userName
-
Field Details
-
TOKEN_EXPIRED
- See Also:
-
-
Constructor Details
-
HttpServletAuthService
public HttpServletAuthService()
-
-
Method Details
-
getRequest
public abstract jakarta.servlet.http.HttpServletRequest getRequest()获取HttpServletRequest对象子类必须实现此方法以提供HTTP请求上下文
- Returns:
- HttpServletRequest实例
-
getResponse
public abstract jakarta.servlet.http.HttpServletResponse getResponse()获取HttpServletResponse对象子类必须实现此方法以提供HTTP响应上下文,用于设置Cookie
- Returns:
- HttpServletResponse实例
-
userDetailService
获取用户详情服务子类必须实现此方法以提供用户详情服务实例
- Returns:
- UserDetailService实例
-
jwtEncoder
-
jwtDecoder
-
cookieSettings
获取Cookie配置默认返回空的Cookie配置,子类可以重写以自定义配置
- Returns:
- CookieSettings实例
-
tokenKey
获取Token的键名可以从Header、Cookie或请求参数中获取,此方法返回键名 默认使用Cookie配置中的Token Cookie名称
- Returns:
- Token键名
-
refreshTokenKey
获取Refresh Token的键名可以从Header、Cookie或请求参数中获取,此方法返回键名 默认使用Cookie配置中的Refresh Token Cookie名称
- Returns:
- Refresh Token键名
-
token
获取当前用户的访问令牌(Token)按优先级从不同位置获取Token: 1. Cookie中的Token 2. Authorization Header 3. 自定义Header(使用tokenKey) 4. 请求参数(H10:默认禁用,需子类覆写
allowQueryToken()返回 true 才启用)- Specified by:
tokenin interfaceAuthService- Returns:
- Token字符串,如果未找到则返回空字符串
-
refreshToken
获取当前用户的刷新令牌(Refresh Token)按优先级从不同位置获取Refresh Token: 1. Cookie中的Refresh Token 2. Header中的Refresh Token 3. 请求参数中的Refresh Token(H10:默认禁用,需覆写
allowQueryToken()返回 true 才启用)- Specified by:
refreshTokenin interfaceAuthService- Returns:
- Refresh Token字符串,如果未找到则返回空字符串
-
allowQueryToken
protected boolean allowQueryToken()是否允许从 URL 查询参数中获取 Token(H10)默认返回 false(禁止)——Token 走 query 会进入浏览器历史、访问日志、Referer,泄露面大。 确需支持(如旧客户端/文件下载场景)时,子类覆写返回 true;框架默认安全。
- Returns:
- true 表示允许从 query 参数取 Token,默认 false
-
tokenOrRefreshToken
获取有效的Token(优先Access Token,否则使用Refresh Token)先检查Access Token是否有效,如果无效则尝试使用Refresh Token
- Returns:
- 有效的Token字符串
-
subject
获取当前会话的Subject(主题)从tokenOrRefreshToken()中解析Subject信息 如果解析失败,返回空字符串
M9: 仅解析验签通过的 token——tokenOrRefreshToken() 在 access token 失效时回退返回 refresh token(未验签),未验签 token 的 subject 不可信,直接返回空串
- Specified by:
subjectin interfaceAuthService- Returns:
- Subject字符串,解析失败时返回空字符串
-
token
为指定用户生成访问令牌- Specified by:
tokenin interfaceAuthService- Parameters:
subject- 用户标识- Returns:
- 生成的访问令牌
-
refreshToken
为指定用户生成刷新令牌- Specified by:
refreshTokenin interfaceAuthService- Parameters:
subject- 用户标识- Returns:
- 生成的刷新令牌
-
login
用户登录执行登录操作: 1. 将Token和Refresh Token写入Cookie 2. 通过UserDetailService保存用户信息
- Specified by:
loginin interfaceAuthService- Parameters:
user- 用户信息对象(包含Token和Refresh Token)- Returns:
- 登录后的用户信息
-
logout
public void logout()用户登出清除Cookie中的Token和Refresh Token,使其失效
- Specified by:
logoutin interfaceAuthService
-
user
获取当前登录用户执行流程: 1. 如果Token和Refresh Token都为空,返回匿名用户 2. 如果Access Token有效,直接使用它获取用户信息 3. 否则尝试使用Refresh Token刷新
- Specified by:
userin interfaceAuthService- Returns:
- 当前登录用户,未登录时返回匿名用户
-
tryRefreshToken
-
addCookie
-
authentication
URL认证检查检查当前请求是否通过认证,判断逻辑: 1. 如果skip()返回true,直接通过 2. 如果URL匹配白名单Ant路径模式,直接通过 3. 否则检查 access token 是否有效(只读判定,不触发 token 刷新、不写响应 Cookie)
P1-8: 认证检查为只读语义——不再经由
user()的惰性刷新路径(那会静默写 Set-Cookie), access token 过期即判定未认证;刷新由显式调用user()/tryRefreshToken(String)触发- Specified by:
authenticationin interfaceAuthService- Parameters:
withoutAuthenticationUrlRegulars- 不需要检查的URL(Ant路径模式)列表- Returns:
- 认证检查通过状态
-
pass
检查URL是否匹配白名单路径模式先将原始 URI 归一化(
normalizeUri(String)),再遍历所有模式做 Ant 匹配; 归一化失败(含百分号编码或穿越残留)一律返回 false——白名单语义为"无法安全判定即不放行"。P0-2: 原实现直接对
getRequestURI()的原始串做 Ant 匹配,未消解../、 未剥离 matrix 参数、未拒绝百分号编码,攻击者可构造/public/../admin/users或/public/health;jsessionid=x/../admin/users使鉴权看到的路径与容器实际路由的路径不一致,从而绕过白名单。M8: 使用 Ant 路径模式(Spring 语义)——
/api/**匹配任意层级子路径,/health精确匹配;原正则写法(如/swagger-resources.*)请改为 Ant- Parameters:
uri- 请求地址withoutAuthenticationUrlRegulars- 放行URL模式列表- Returns:
- 是否放行
-
skip
public boolean skip()是否跳过认证检查默认返回false,子类可以重写以实现自定义跳过逻辑
- Returns:
- true表示跳过检查,false表示不跳过
-
authorizationHeaderKey
获取认证Header的Key默认返回HttpHeaders.AUTHORIZATION("Authorization") 子类可以重写以使用自定义的Header名称
- Returns:
- 认证Header的Key
-
optionalUser
尝试获取当前认证用户返回Optional包装的用户对象,如果用户为null则返回空Optional
- Specified by:
optionalUserin interfaceAuthService- Returns:
- 包含当前用户信息的Optional
-