type
status
date
slug
summary
tags
category
icon
password
ext
order
comment
前言
由于正在开发的一个后台框架是前后端分离的,后端接口则需要token以便于鉴别用户身份,刚开始时是使用ConcurrentHashMap存储token的,但是它不能持久化,而且需要定时清理过期token,于是后来就换成Redis来存储,可以持久化并且会自动清除过期数据。
什么是Token
Token中文意为令牌,像古代,高官权贵都有一个令牌代表各自的身份,某些人持令牌才可进宫,这个令牌主要作用就是鉴别身份,一亮出牌子,噢~原来是王大人~!快快请进。
Token应该保证唯一不重复,多个用户的token不允许出现重复,我使用的策略是 用户名+姓名+用户ID+当前时间戳 拼接后转为MD5
每次向API请求数据时,都需要带上这个用户的token请求才能进去,具体的流程如下
- 前端发起请求(header或param携带token)
- 后端拦截器拦截请求,解析token是否有效,无效返回错误信息,有效放行
- 控制器中方法成功调用,返回数据
前端Token的使用
首先说下前端,这个token什么时候拿呢?用户第一次登陆时,登录接口返回的数据需要携带token,例如
而前端请求成功后,要将token存储起来,将data属性值通过JSON.stringify()转为字符串,然后存到localStorage或者cookie中都可以,我是存到cookie中并加了过期时间,之后用的时候拿出来再JSON.parse()后取得token属性值再发起请求
前端相对简单很多,具体处理都在后端了,接下来就详细说一下后端如何处理
开始编写后端
一共有两部分
- token相关的service,model和注解
- 重要的拦截器,利用的HandlerInterceptor
- 自定义参数解析,利用HandlerMethodArgumentResolver (用于将token对应的用户model传入控制器方法的参数)
首先新建一个TokenModel,UserModel就不放了,用户id,用户名等等
然后新建一个TokenManager, 用于存储、生成、删除token,redisUtil代码就不放了,就是存取下redis
然后新建TokenService以及TokenServiceImpl,用于根据token获取用户信息,验证token,生成token,删除token
然后新建两个注解,分别是TokenValid和NoTokenValid,因为有些方法不需要token验证,所以用NoTokenValid以用于排除
这个时候就需要重要的拦截器亮相了,拦截器需要实现HandlerInterceptor接口,一般token只在header中取,我会优先再header中取,其次在param中取
拦截器里的思路,判断请求的方法/控制器是否有TokenValid注解和NoTokenValid注解,如果需要Token验证,那么就获取Token,然后解析验证
代码中httpServletRequest.setAttribute(USER, user);也很重要,便于控制器中的方法直接根据参数获取到UserModel ,如下,可以发现这有个@CurrentUser这个东西,下面会讲到
新建CurrentUser
然后创建解析器CurrentUserMethodArgumentResolver ,解析器需要实现 HandlerMethodArgumentResolver 接口
拦截器和自定义参数解析器都创建完毕之后,还需要向spring注册一下才可被使用,新建WebMvcConfig,重写addArgumentResolvers方法,在其中添加currentUserMethodArgumentResolver,重写addInterceptors方法,在其中添加tokenHandleInterceptor
开始使用
注解加于控制器,代表控制器内所有方法都需要验证token
注解加于方法,代表这个方法需要验证token
如果控制器外加了TokenValid,但是里面某个方法不需要Token验证,那么就需要用NoTokenValid
自定义参数解析器的使用,通过@CurrentUser UserModel user参数接收
token验证做完之后,可以再创建个拦截器,用于限制用户访问权限,没必要再发文章了,我是根据URL判断用户是否拥有该菜单权限。
至此,结束.
- 作者:Loneking
- 链接:https://loneking.cn/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/86
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。