在我们平时登录注册的过程中,我们的信息都会由浏览器发送给后端进行处理,然后再插入到数据库中,下次我们进行登录的时候,只需要输入用户名和密码就可以登录成功进入网站进行操作了。
但个人信息暴露在大众面前这是极其不安全的,对于我们的隐私,我们并不希望被别人知道。所以我们在登录的时候,浏览器中进行传递的数据有些是会脱敏、有些是需要进行加密之后才能进行传递的。
JWT(全称JSON WEB Token):是实现token的机制。,是一种用于安全传输信息的紧凑、URL安全的令牌格式,通常用于身份验证和授权。
JWT由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)。
头部:包含令牌的元数据,例如使用的加密算法和令牌类型等。
载荷:包含声明(Claims),即要传递的信息,如用户ID、角色、过期时间等。
签名:用于验证消息在传递过程中是否被篡改,它是通过将头部和载荷进行Base64编码后,使用指定的签名算法和一个密钥生成的。
Token是用于身份验证和授权的令牌,保证只有经身份验证和授权的用户才能访问特定的资源。可提高安全性。
用户使用用户名和密码进行登录,服务器验证用户信息是否正确。
服务器生成一个JWT,将用户信息、权限等信息写入载荷中,并使用密钥对头部和载荷进行签名。
服务器将生成的JWT返回给客户端,客户端将其存储在本地。客户端在后续请求中,将JWT作为请求头部或请求参数传递给服务器。
服务器收到请求后,验证JWT的签名是否正确,如果正确则解析出用户信息、权限等信息,进行后续操作。
com.auth0
java-jwt
3.19.0
cn.hutool
hutool-all
5.7.4
import cn.hutool.core.date.DateUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.yupi.model.domain.User2;
import com.yupi.service.User2Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class JwtUtil {
@Autowired
User2Service user2Service;
/**
* 创建jwt
* @param user
* @return
*/
public String createToken(User2 user){
String sign = JWT.create()
// 设置载荷
.withAudience(user.getId().toString())
// 设置签名过期的时间:24小时后
.withExpiresAt(DateUtil.offsetHour(new Date(), 24))
// 设置签名密钥 Signature
.sign(Algorithm.HMAC256(user.getUserPassword()));
return sign;
}
/**
* 校验Token,返回用户信息
* @param token
* @return
*/
public User2 verify(String token){
DecodedJWT decode = JWT.decode(token);
String userId = decode.getAudience().get(0);
User2 user = user2Service.getById(userId);
//获取校验器
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getUserPassword())).build();
jwtVerifier.verify(token);
return user;
}
}
这段生成签名的方法形式和上篇API签名认证的签名生成方式差不多
生成签名方法:
JWT.create()
创建一个新的JWT对象。withAudience()
方法来设置载荷,将用户的ID转换为字符串并作为载荷传递给该方法。withExpiresAt()
方法设置签名的过期时间,这里设置为当前时间加上24小时。sign()
方法对JWT进行签名,签名算法使用的是HMAC-SHA256算法,密钥是用户的密码。sign
中,并返回给调用者。在这里同样密码也是不在浏览器中进行传递的,是从数据库中获取的
校验签名方法:这个方法的作用是验证传入的JWT令牌是否有效,并返回对应的用户信息。
JWT.decode(token)
方法对传入的令牌进行解码,得到一个DecodedJWT
对象。decode.getAudience()
方法获取令牌中的用户IDJWT.require()
方法,构建一个JWT验证器。这个验证器可以用来验证JWT令牌的有效性。jwtVerifier.verify(token)
方法验证令牌是否有效。如果令牌有效,则该方法不会抛出异常;否则,会抛出异常。这里和我们上一篇的API签名认证稍有不同,API签名认证里面是我们通过获取到的密钥再次生成签名,然后拿两个签名去比较。而这里,我们是通过用户密码(密钥)去创建了一个校验器,然后去验证JWT。
通俗一点来讲,我们之前是使用钥匙配好了一把锁,然后我们是去配另一把锁,如果匹配上,那这两把锁就是相同的。现在我们是拿另一把钥匙去匹配同一把锁,如果匹配上,那说明这把钥匙和之前那把就是一样的。
总结一下步骤:
输入用户名和密码发起请求,然后根据用户名和密码和数据库中进行比对实现登录,
获取到user对象,然后使用jwtUtil
工具类中的创建签名方法来生成token
登录的逻辑这里就不写了,就是去数据库查询
@GetMapping("/jwt/login")
public String jwtLogin(UserLoginRequest userLoginRequest, HttpServletRequest request){
String userAccount = userLoginRequest.getUserAccount();
String userPassword = userLoginRequest.getUserPassword();
User2 user = userService.userLogin(userAccount, userPassword, request);
String token = jwtUtil.createToken(user);
return token;
}
请求成功
从request的请求头中获取token,然后通过签名工具类获取到用户信息返回
@GetMapping("/jwt/test")
public User jwtTest(HttpServletRequest request) {
String token = request.getHeader("Authorization");
User user = jwtUtil.verify(token);
return user;
}
JWT登录验证成功
今天我的分享到此结束,欢迎大家点赞、评论、关注!!!