Java 后端应用程序使用 Spring-security 实现基于 JWT 的身份验证和授权,这是一个概念验证项目,利用 Spring-security 实现基于 JWT 的身份验证、API 访问控制、Token 撤销和泄露密码检测。
新发布的 Spring Security 6.3 版本添加了密码泄露检测功能,本项目提供的默认实现在底层使用了Have I Been Pwned API 。
向安全端点发出的任何请求都会被 JwtAuthenticationFilter.java 拦截,JwtAuthenticationFilter 会添加到安全过滤器链中,
并在 SecurityConfiguration.java 中进行配置。自定义过滤器负责验证传入访问令牌的真实性并填充安全上下文。
关键组件:
- 公共 API 声明:ApiEndpointSecurityInspector.java
- Token配置:TokenConfigurationProperties.java
- Token生成:JwtUtility.java
公共 API 声明
任何需要公开的 API 都可以用@PublicEndpoint进行注释。自定义安全过滤器不会评估对已配置 API 路径的请求,其逻辑由ApiEndpointSecurityInspector.java控制。
下面是一个声明为公共的示例控制器方法,它将免于身份验证检查:
@PublicEndpoint |
Token生成和配置
应用程序使用访问令牌 (JWT) 和刷新令牌,身份验证成功后,这两个令牌都会返回给客户端。JWT 使用 RS512 非对称密钥对进行签名和验证,其中私钥(PKCS#8 格式)用于签名,相应的公钥用于在调用私有端点时进行验证,这些操作由JwtUtility.java处理。
刷新令牌是RefreshTokenGenerator生成的随机 256 位值,并由AuthenticationService根据用户标识符存储在缓存中。
可以在活动文件中配置令牌有效性/到期时间(以分钟为单位)和非对称密钥对.yml。配置的值填充在TokenConfigurationProperties中并由应用程序引用。以下是示例代码片段。
com: |
API 访问控制
应用程序根据用户在系统中的当前状态实施访问控制。相应的权限嵌入到生成的 JWT 中,从而实现无状态的访问控制和授权过程。
泄露密码检测
为了保护用户帐户免遭在数据泄露中暴露的易受攻击的密码攻击,该项目使用了 中新增的泄露密码检测功能spring-security:6.3。提供的默认实现在底层使用了Have I Been Pwned API 。
泄露密码检查在两个关键场景中进行:
- 用户创建:通过用户创建 API 注册新用户时,将检查提供的密码。
- 用户登录:即使在创建用户时密码未被泄露,但密码也可能在之后被泄露。为了解决这个问题,登录 API 还加入了密码泄露检查。
{ |
为了在登录期间恢复密码泄露的情况,/users/reset-password我们公开了一个新的 API 端点 PUT。此端点接受以下请求主体负载:
{ |
在允许重置密码之前,还会检查新密码是否被破解。