由于HTTP的无状态性,我们无法判断是哪个客户端在请求接口。这里我们把用户看成是客户端,客户端使用用户名还有密码通过了身份验证,不过下回这个客户端再发送请求时候,还得再验证一下。
解决的方法就是,当用户请求登录的时候,如果没有问题,我们在服务端生成一条记录,这个记录里可以说明一下登录的用户是谁,然后把这条记录的 ID 号发送给客户端,客户端收到以后把这个 ID 号存储在 Cookie 里,下次这个用户再向服务端发送请求的时候,可以带着这个 Cookie ,这样服务端会验证一个这个 Cookie 里的信息,看看能不能在服务端这里找到对应的记录,如果可以,说明用户已经通过了身份验证,就把用户请求的数据返回给客户端。
上面说的就是 Session,我们需要在服务端存储为登录的用户生成的 Session ,这些 Session 可能会存储在内存,磁盘,或者数据库里。我们可能需要在服务端定期的去清理过期的 Session 。
但是有些情况下session并不那么好用,一个是session会占用后端内存资源,还有如果用户cookie中的sessionId被窃取,很容易就可以获取用户的私有数据.这时我们可以用token来解决这些问题
使用基于 Token 的身份验证方法,在服务端不需要存储用户的登录记录。大概的流程是这样的:
实际上,JWT的Token就是 JSON数据转换后的一串字符串 JWT主要包括三个部分:header(头部)payload(数据)signature(签名)
{
"alg": "HS256",
"typ": "JWT"
}
alg属性表示签名使用的算法,默认为HMAC SHA256(写为HS256);typ属性表示令牌的类型,JWT令牌统一写为JWT
{
"id": 1,
"username": "wintershii",
"passwd": "",
"admin": true
}
最终我们将这三部分内容用"."分开,并用Base64编码
作为一个后端为SSM框架的项目,首先现在pom.xml中引入依赖
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.5.0</version>
</dependency>
然后编写Token工具类
public class TokenUtil {
//token有效时间
private static final long EXPIRE_TIME = 15 * 60 * 1000;
private static final String TOKEN_SECRET = "thefirsttoken777";//这里填写私匙
/**
* 颁发签名
* @return
*/
public static String sign(Integer id, String phone) {
try {
// 设置过期时间
Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
// 私钥和加密算法
Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
// 设置头部信息
Map<String, Object> header = new HashMap<>(2);
header.put("Type", "Jwt");
header.put("alg", "HS256");
// 返回token字符串
return JWT.create()
.withHeader(header)
.withClaim("id",id.toString())//在这里可以放自己需要放的数据
.withClaim("phone",phone)
.withExpiresAt(date)
.sign(algorithm);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 检验token是否是正确格式(是否过期,是否可用)
* @param token
* @return
*/
public static boolean verify(String token){
try {
Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
JWTVerifier verifier = JWT.require(algorithm).build();
DecodedJWT jwt = verifier.verify(token);
return true;
} catch (Exception e){
return false;
}
}
/**
* 从token中获取相关信息
* @param token
* @return
*/
public static String getInfo(String token ,String type){
try {
DecodedJWT jwt = JWT.decode(token);
if (type.equals("phone")) {
return jwt.getClaim("phone").asString();
}
if (type.equals("id")) {
return jwt.getClaim("id").asString();
}
} catch (JWTDecodeException e){
e.printStackTrace();
return null;
}
return null;
}
}
根据上面的TokenUtil,在用户登录后,我们可以签发给该用户Token,并将其添加到响应头(或者在响应体里加也可以),然后下次客户端请求我们的时候就要带着这个Token来请求接口
/**
* 用户登录
* @return
*/
@RequestMapping(value = "/login.do",method = RequestMethod.POST)
@ResponseBody
public ServerResponse<User> login(String phone, String password, HttpServletResponse response) {
ServerResponse<User> serverResponse = userService.login(phone,password);
if (serverResponse.isSuccess()) {
Integer id = serverResponse.getData().getId();
//生成Token
String token = TokenUtil.sign(id,phone);
if (token != null) {
//添加到响应头中
response.addHeader("token",token);
return serverResponse;
}
}
return ServerResponse.createByErrorMessage("登录失败");
}
那么如何判断请求是否带有Token呢?我们当然可以在每个Controller中都进行判断,但是这也太麻烦了,这时我们想到了过滤器,也就是Spring MVC拦截器.我们把除了注册,登录这些不需要用户登录的接口的其他接口用拦截器拦截,并检测其请求头中是否带有Token信息
/**
* token拦截器
*/
@Component
public class TokenInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
response.setCharacterEncoding("utf-8");
String token = request.getHeader("token");
if (token != null){
boolean result = TokenUtil.verify(token);
if(result){
System.out.println("通过拦截器");
return true;
}
}
System.out.println("认证失败");
return false;
}
}<!--配置拦截器-->
<mvc:interceptors>
<!--<bean class="com.ma.interceptor.CustomeInterceptor" />-->
<!--拦截器1-->
<mvc:interceptor>
<!--配置拦截器的作用路径-->
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/user/register.do"/>
<mvc:exclude-mapping path="/user/login.do"/>
<!--定义在<mvc:interceptor>下面的表示匹配指定路径的请求才进行拦截-->
<bean class="com.winter.interceptor.TokenInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
下面是spring mvc配置文件中的拦截器相关注解
<!--配置拦截器-->
<mvc:interceptors>
<!--<bean class="com.ma.interceptor.CustomeInterceptor" />-->
<!--拦截器1-->
<mvc:interceptor>
<!--配置拦截器的作用路径-->
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/user/register.do"/>
<mvc:exclude-mapping path="/user/login.do"/>
<!--定义在<mvc:interceptor>下面的表示匹配指定路径的请求才进行拦截-->
<bean class="com.winter.interceptor.TokenInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
这样我们就可以使用Token进行会话了,但当我们需要进行某些敏感操作(删除,修改信息)时,我们需要在Controller中解析Token中的数据,并将其与要操作的用户数据进行对比,如果不是同一用户的数据,那就拒绝操作,返回失败.
最后,因为JWT如果被窃取,服务器也没有办法去识别,所以为了减少盗用和窃取,JWT不建议使用HTTP协议来传输代码,而是使用加密的HTTPS协议进行传输。
Maven导入本地JAR包操作步骤_maven3.5.1
for (int j = 0; j < this.dataGridView1.Rows.Count; j++) { if (this.dataGridView1.SelectedRows.Count > 0) { DataRowView drv = this.dataGr
springboot 查看数据库连接池_springboot查看連接池 hkir
1.设置预览方向myCamera.setDisplayOrientation(90)2.设置照片方向parameters.setRotation(90);3.设置预览显示和照片的分辨率 // 设置照片分辨率 List previewSizeList = parameters .getSupportedPreviewSizes(); int previewWidth = 0;_android camera parameters.setrotation
This program demonstrates how to perform a non calibratedmeasurement by using the sheet-of-light technique用激光三角测量技术实现一个无标定的测量,主要为一下三步At first, a sheet-of light model is created and suitable paramete
人力资源管理的五大职能分别是获取、整合、保持、评价和发展。 1、获取 根据企业目标确定的所需员工条件,通过规划、招聘、考试、测评、选拔、获取企业所需人员。 获取职能包括工作分析、人力资源规划、招聘、选拔与使用等活动。 a.工作分析:是人力资源管理的基础性工作。在这个过程中,要对...
parentView.bringSubview(toFront: childView)其实就这么一句话,parentView代表父容器,childView代表子View,也就是你想放到最上层的View查看原文:https://www.liuandy.cn/ios/2018/01/17/2274.html
程序执行需要读取到安全敏感项必需在androidmanifest.xml中声明相关权限请求, 完整列表如下: android.permission.ACCESS_CHECKIN_PROPERTIES允许读写访问”properties”表在checkin数据库中,改值可以修改上传( Allows read/write access to the “properties” table in t
关于elementUI upload组件上传图片时携带token的方法利用Upload组件中有一个header属性直接上代码html:<el-form-item label="头像" :label-width="formLabelWidth" prop="avatar"> <el-upload v-if="dialogStatus == 'create'" ref="u..._element ui上传图片怎么带jwttoken
我正在使用OpenCV 3.1.0-dev和python 2.7.我试图裁剪出我缝制的图像的黑色外观.困难在于图像中还有其他像素为黑色,因此cv2.findcontours返回一个非常有趣的numpy数组. 第一张图片是我的,第二张图片是目标.我想知道是否有人知道如何将多边形裁剪到包含整个图像的最小正方形中.蓝线和点是cv2.findContours找到的轮廓.是否可以在numpy数组中找到左上角..._numpy 切子图
IEEE 802.11b标准简析 (转)[@more@]IEEE 802.11b标准简析(作者:李伟 2001年02月14日 09:44) 以往,无线局域网发展缓慢,推广应用困难,主要是由于传输速率低、成本高、产品系列有限,且...
public function gzdecode ($data) { $flags = ord(substr($data, 3, 1)); $headerlen = 10; $extralen = 0; $filenamelen = 0; if ($flags & 4) { $extralen = unpack('v' ,substr($da_php ungzip 解压缩post 参数