零. 序
更新完了,but前端学不动了orz
说明:本篇笔记主要是为了后面复习的时候,再走一遍流程的。
一. 验证登录
传统用session
验证
前后端分离后使用jwt
验证
登录验证的机制
url的权限上大致可以分成2类
- 公开页面(未公开可以)login页面——与数据库一致,给用户发一个sessionID,用户存到cookie中,每次请求访问时,将cookie中的session发给服务器
- 授权页面(登录后部分用户可见)—— 提取cookie中的sessionID,判断是否有效,如果有效,则提取对应的用户信息到上下文中(一个url对应一个Controller)
登录以后如何授权用户?(登录以后不关浏览器,就能请求访问其他页面)
现在:多端,跨域,多服务器分布式端 —— sessionID难用
JWT验证
JWT全称json web token
好处:容易跨域,容易在多个服务器端使用。
原理:
现在服务器要给用户一个jwt-token,将用户信息加入到jwt-token中(比如第一段存用户信息userid,第二段是密钥(别人看不到),用哈希算法或加密算法不可逆地变成一个加密后的字符串。
将用户信息和加密后的信息合并返回给用户,即为JwtToken
服务器判断:拿userid+密钥 加密后和加密后信息进行比对
问题:
用户篡改信息怎么办?用户改了userid没有密钥,无法得到加密后的结果
减少被盗的方式:服务器一般给用户传2个token:
access_token
: 5min 用时间短的令牌 进行get post请求 get信息易暴露
refresh-token
: 14天 快过期的时候,用post进行更新access_token
(项目中只发accesstoken,为了方便项目开发)
字符串变加密字符串,给定jwt并解析jwt
添加依赖
jjwt::api
jjwt-impl
jjwt-jackson
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-api -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-impl -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-jackson -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
复制工具类代码
实现utils.JwtUtil
类,为jwt
工具类,用来创建、解析jwt token
实现config.filter.JwtAuthenticationTokenFilter
类,用来验证jwt token
是否合法,如果验证成功,则将User
信息注入上下文中
配置config.SecurityConfig
类,放行登录、注册等接口
二. 后端API
- 登录API
- 获取信息
- 注册账号
修改数据库:
- 将数据库中的
id
域变为自增- 在数据库中将
id
列变为自增 - 在
pojo.User
类中的id
属性上添加注解:@TableId(type = IdType.AUTO)
- 在数据库中将
- 加一个头像字段
photo
:不存文件,而是存储图片的连接(云床) - 实现
/user/account/token/
:验证用户名密码,验证成功后返回jwt token
(令牌) - 实现
/user/account/info/
:根据令牌返回用户信息 - 实现
/user/account/register/
:注册账号
所有的api都会返回json数据
1.获取jwtToken API
写API只需要写3个地方
1.Service写接口
2.impl实现接口
3.Controller调Service
登录通常是post请求,是看不到明文的,而get会将用户名密码明文放到url上
1.LoginService.java
代码略
2.LoginServiceImpl.java
代码略
3.LoginController.java
代码略
在Controller中定义完Mapping后记得在filter中放行
写完Controller后,可以运行一下,但是问题出现了
在浏览器上输入url进行访问,发起的是get请求,而我们写的是接收post请求,导致请求时报错405——方法不允许
解决方法:
1.postman等接口调试工具来调试
2.前端ajax发送post请求调试
测试接口
代码略
过程中碰到一个异常,和y总的不一样
java.lang.IllegalArgumentException: Last unit does not have enough valid bits
原因在于public static final String JWT_KEY = "xxxx";
的长度不是4的倍数,或者有可能是特殊字符丢失
修改以后得到结果
在F12开发者工具中得到Token,在jwt.io可以解析jwttoken
2.获取当前用户的信息 API
1.service接口
代码略
2.impl接口的实现
代码略
3.controller
代码略
测试接口
Authorization授权
Authentication认证
代码略
结果
3.用户注册账号API
1.RegisterService.java
代码略
2.RegisterServiceImpl.java
代码略
3.RegisterController.java
代码略
测试脚本
代码略
刷新测试结果
三. 前端用户登录页面
前端需要实现两个页面
在views/user/acount
下实现
登录页面的前端样式
UserAccountLoginView.vue
加入到router路径中:在index.js
下
代码略
在bootstrap找个样式 grid
grid会将页面分成12格,要把布局放到中间三格中
代码略
再搜一个表单
的样式
代码略
需要用view存储一些全局的用户信息
可以写在store/user.js
下
代码略
然后将user.js
的Module导入到store/index.js
代码略
UserAccountLoginView.vue
代码略
登录成功以后可以将获得的username
放到导航栏上
如果没有登录,则显示登录和注册
如果登录成功显示用户名
退出页面
Token
是完全存在用户端本地的,服务器端没必要存,只需要存一个过期时间
退出登录的逻辑:用户自己把token
删掉,就无法请求访问服务器了
在user.js
中的mutations
下写一个logout
的逻辑,用来更新state
,使用户信息都清空,并在actions
中调用
代码略
在NavBar
中也要写退出脚本的逻辑
代码略
并在html中更新退出按钮的点击事件
代码略
如何限制只能一个设备登录?
在数据库中存每个用户的token,判断当前存着的token有多少,如果有多于1个,则把前一个注销掉。
用户再重新用原设备登录时判断此时用户的token是否在注销掉的部分中,如果有就恢复出来,并注销其他token
在数据库中开一个表或者列,存 给用户分配的最新的token是哪个,每次给用户发token的时候更新一下新token
另外退出以后应该重定向到首页或者登录页面
另外现在还有一个问题:token存于用户浏览器内存中,一刷新就会退出
解决:将token放到router/store中,这样刷新和关闭就不会取消登录状态
再加一个功能:
用户在没有登录的时候访问其他页面会自动跳转登录页面
注册页面的前端样式
UserAccountRegisterView.vue
下节预告:1.个人中心页面 2.bot代码的添加修改删除
Orz
大佬 图片显示不了
更新了,就是y总上课手画的图hh