JWT登录认证-项目BotBattle
对于 url 可以分为两大类:
- 公开可以访问(本项目中,对于登录和注册的 URL,公开可以访问)
- 需要授权才能访问
实现目标:在没有判断登录认证的情况下,访问任意界面,直接跳转到登录界面。
添加Spring Security
依赖来实现登录认证
sessionID 授权认证
实现config.SecurityConfig
类
SessionID 相当于给浏览器颁发的一张临时身份证,之后浏览器在执行业务操作的时候,都要随身携带这个身份证。
1.sessionID 生成与保存
服务器会在用户登录时创建一个唯一的会话标识(sessionID),并将其存储在服务器端的内存或者数据库中,然后将 sessionID 发送给客户端并存储在客户端的Cookie中。
2.sessionID 和请求一起传送给后端
客户端在后续的请求中都会携带这个 sessionID,在服务器端会根据 sessionID 去验证用户的身份。
客户端每次向后端 Springboot 发送请求的同时,会从 Cookie 中取出将 SessionID 一起传送给后端 Springboot。Springboot 通过向数据库查询判断当前 SessionID 是否存在以及是否过期
-
PS:后端查询判断
如果存在,将有关 SessionID 的信息(包括对应的用户名、过期时间)从数据库中取出,判断是否过期。
若 SessionID 过期或者根本不存在,则返回给用户登录页重新登录。
若 SessionID 没有过期,则通过 SessionID 与用户信息 userInfo 的映射关系,将对应的 User 提取到上下文中(在 Contoller 中就可以通过一些 API 来拿到 User),成功进行授权页面的访问。
对于前后端分离的情况,使用 session 可能会出现跨域问题。
浏览器的同源策略(Same-Origin Policy)限制了来自不同源(即不同的协议、域名或端口)互相之间的某些操作。
想象你住在一个严格管理的小区里(浏览器),而小区有一条规定:你只能和住在同一栋楼里的邻居(同源服务器)自由交流和分享东西(数据请求)。现在,你想要和住在隔壁楼的一个邻居交换东西(跨域请求),但是物业(浏览器的同源策略)不允许你这么做,除非隔壁楼的邻居明确告诉物业,他们愿意接受你,并且确认这次交换是安全的(CORS 策略)。如果你想通过物业的特殊通行证(Cookie)证明你的身份来进行这次交换,物业还需要验证这个通行证是不是也被邻居接受的(允许携带 Cookie 的跨域请求)。在使用 Session 认证时,如果没有正确处理这些安全策略,你就无法成功地和不同楼栋的邻居交换东西了。
比如 Ajax 请求数据。当你的前端应用尝试从一个源向另一个源的服务器发送请求时,就会遇到跨域问题。
JWT(JSON Web Token)验证 的无状态认证机制
JWT 用户的认证信息(例如用户 ID、Token 的发行者、过期时间)以 JSON 格式编码,并使用签名密钥进行加密,生成一个 Token,然后将这个 Token 发送给客户端。客户端在后续的请求中都会携带这个 Token,在服务器端可以解析 Token 并验证用户的身份。
Token 被存储在客户端的浏览器中,通常是在 HTTP 请求的头部(Header)中
服务器不需要保存任何用户状态信息,只需要验证这个 Token 的签名来认证用户的请求。用户状态信息,服务器不需要保存,就是“无状态的认证机制”的“无状态”。
jwt 验证的优点
- 容易实现跨域
- 不需要在服务器端存储
- 对于有多个服务器的情况,就可以实现用一个令牌来登录多个服务器
密码存储与加密
在config.SecurityConfig
类中,实现用户密码的加密存储
放行登录、注册等接口
如果直接用明文密码来存储,需要在数据库中加上{noop}
标记,代表不需要加密直接判断
-
BCrypt 是 一种用于密码哈希的安全算法。借助
BCryptPasswordEncoder
的encode()
方法更新数据库中的明文密码 -
要在添加阶段就直接存储加密阶段的代码,用到 PasswordEncoder
实践与调试
添加依赖:
jjwt-api
jjwt-impl
jjwt-jackson
实现utils.JwtUtil
类,创建、解析 jwt token
实现config.filter.JwtAuthenticationTokenFilter
类,用来验证 jwt token 是否合法有效,如果验证成功,则将 User 信息注入上下文中
配置config.SecurityConfig
类,放行登录、注册等接口
登录一般是 post 请求。
登录如果是 get 请求,会将用户名和密码参数放在 url 链接中,明文传输。显然不能这样。
选择 Post 请求,就没法从浏览器输入 URL 的方式进行访问,不能在浏览器中调试。有 2 种调试方式
- 前端 ajax 调试
- 用 postman(以后学习)
对于返回的 token
比如:
"eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI5OWE5ZThjZDNlZDI0OTI3YTZiMWMzNDk5MDU1ZDljMyIsInN1YiI6IjEiLCJpc3MiOiJzZyIsImlhdCI6MTY1ODk3MjYzMCwiZXhwIjoxNjYwMTgyMjMwfQ.iioSQLuAyzpYLPzTgGuhs1ODb6mYIzpqnz6K8VQqbWc"
在https://jwt.io/进行解析,可以得到对应的 userID。