Shiro与JWT整合实现分布式认证

Shiro与JWT整合实现分布式认证

一、思路

shiro 用来认证用户及权限控制,jwt用来生成一个token,暂存用户信息。

为什么不使用session而使用jwt?传统情况下是只有一个服务器,用户登陆后将一些信息以session的形式存储服务器上,

然后将sessionid存储在本地cookie中,当用户下次请求时将会将sessionid传递给服务器,用于确认身份。

但如果是分布式的情况下会出现问题,在服务器集群中,需要一个session数据库来存储每一个session,提供给集群中所有服务使用,且无法跨域(多个Ip)使用。

jwt是生成一个token存储在客户端,每次请求将其存储在header中,解决了跨域,且可以通过自定义的方法进行验证,解决了分布式验证的问题。

缺点:无法在服务器注销、比sessionid大占带宽、一次性(想修改里面的内容,就必须签发一个新的jwt

二、废话不多说上代码

pom.xml

重构token生成继承 AuthenticationToken

自定义过滤器,继承 AuthenticatingFilter

配置config

shiroFilter管理

shiro配置类

token工具生成类

到此项目差不多搞定

项目源码:源码好的,我们继续完善这个基于 Shiro + JWT 的认证授权系统。接下来将补充核心的领域(Realm)实现、登录控制器以及一些必要的配置和工具类。


三、核心实现

1. 自定义 Realm(Oauth2Realm

Realm 是 Shiro 的核心组件,用于处理认证(登录)和授权(权限检查)。我们需要自定义一个 Realm 来处理 JWT Token。

2. 登录控制器(LoginController

提供一个简单的登录接口,验证用户名密码后签发 JWT。

3. 全局异常处理(可选但推荐)

统一处理 Shiro 抛出的认证授权异常,返回友好的 JSON 格式错误信息。


四、总结与使用

至此,一个基于 Spring Boot + Shiro + JWT + Redis 的无状态分布式认证授权系统就搭建完成了。

核心流程总结:

  1. 登录 (/login):用户提供凭证,服务器校验通过后,生成 JWT 并返回给客户端,同时在 Redis 中存储一份(用于后续刷新和黑名单机制)。
  2. 访问API:客户端在请求头 Authorization 中携带 JWT。
  3. 过滤 (Oauth2Filter):自定义过滤器拦截请求,提取 JWT,并调用 subject.login(token) 发起认证。
  4. 认证 (Oauth2Realm):Realm 验证 JWT 的有效性(签名、过期时间)。
  5. 授权 (Oauth2Realm):认证通过后,Realm 根据 JWT 中的信息(或查询数据库)为用户授予角色和权限。
  6. 权限校验:Shiro 的注解(如 @RequiresRoles, @RequiresPermissions)或 URL 配置会拦截无权限的访问。
  7. 登出 (/logout)(可选):将 JWT 加入黑名单或删除 Redis 中的有效记录,使 token 提前失效。

如何使用:

  1. 在需要权限的控制器方法上添加 Shiro 注解:
    java
    @RequiresPermissions("user:read")
    @GetMapping("/user/info")
    public AjaxResult getUserInfo() {
        // ...
    }
    
  2. 前端在请求需要认证的 API 时,在 Header 中设置:
    text
    Authorization: your_jwt_token_string
    

注意事项:

  • JWT 安全性:确保使用强密钥(SECRET_KEY)且妥善保管。考虑定期更换密钥。
  • 敏感信息:不要在 JWT Payload 中存储敏感信息(如密码明文),因为它是可解码的。
  • Token 失效:由于 JWT 的无状态性,实现即时失效较复杂。文中提供了基于 Redis 黑名单的示例,但会增加系统状态性。请根据业务需求权衡。
  • 性能:如果每次授权都需要查询数据库获取实时权限,可能会影响性能。可以考虑将权限信息也放入 JWT,但牺牲了实时性。

项目源码已提供,可以根据实际业务需求进行进一步的调整和优化,例如集成数据库用户查询、更复杂的权限

Spring IOC与AOP源码解析
Shell脚本命令参数使用指南

评论区

评论加载中...