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