为什么用 Token
一般来说都是用 session 来存储登录信息的,但是移动端使用 session 不太方便,所以一般都用 token 。另外现在前后端分离,一般都用 token 来鉴权。用 token 也更加符合 RESTful 中无状态的定义。
交互流程
- 客户端通过登录请求提交用户名和密码,服务端验证通过后生成一个 Token 与该用户进行关联,并将 Token 返回给客户端。
- 客户端在接下来的请求中都会携带 Token,服务端通过解析 Token 检查登录状态。
- 当用户退出登录、其他终端登录同一账号(被顶号)、长时间未进行操作时 Token 会失效,这时用户需要重新登录。
程序示例
Token的生成算法
服务端生成的 Token 一般为随机的非重复字符串,根据应用对安全性的不同要求,会将其添加时间戳(通过时间判断 Token 是否被盗用)或 url 签名(通过请求地址判断 Token 是否被盗用)后加密进行传输。因为只是个 demo,所以这里简单写了
1 | public class TokenUtil { |
Token的CRUD操作
Redis 是一个 Key-Value 结构的内存数据库,用它维护 userId 和 Token 的映射表会比传统数据库速度更快,这里使用 Spring-Data-Redis 封装的 RedisTokenManager 对 Token 进行基础操作:
首先定义一个 DAO 接口
1 | package com.owen.favorite.repository; |
然后是实现类
1 | package com.owen.favorite.repository.impl; |
登录与注册
登录与注册的 Controller
1 | package com.owen.favorite.controller; |
token验证
客户端访问一些需要用户登录之后才能调用的接口,比如在数据库中插入一条记录,那么就需要判断 token 的合法性。而这样的接口又有很多,那么岂不是每一次都需要及你想那个判断,代码要重复写很多遍。这时候可以使用自定义注解和拦截器来实现。
首先定义一个注解
1 | package com.owen.favorite.anno; |
拦截器的实现
1 | package com.owen.favorite.interceptor; |
一些细节
- 登录请求一定要使用 HTTPS,否则无论 Token 做的安全性多好密码泄露了也是白搭
- Token 的生成方式有很多种,例如比较热门的有 JWT(JSON Web Tokens)、OAuth 等。