什么是jwt?
jwt(json web token),简单来说就是:web领域中基于json格式的令牌。是最常用的令牌规范。
- 第一部分:header(头),指定了令牌的签名算法、令牌类型。
- 第二部分:payload(有效载荷),使用base64来编码的,不是加密算法,能够解码。因此,该部分不适合存放用户的私密信息(如:密码)。
- 第三部分:signature(签名),将第一部分和第二部分通过密钥加密得到。
解析token可以根据第三部分解密得到前两部分的信息,再比对前端传来的用户信息,完成校验。
token验证失败的情况?
token过期
密钥不正确
篡改了头部、载荷等
为什么需要令牌?
- 承载了一定的数据信息,减少数据库访问次数
- 具有一定的防伪功能
如何实现?
该部分代码不需要硬记,理解后直接使用即可。
添加依赖:
<dependency> <groupid>io.jsonwebtoken</groupid> <artifactid>jjwt</artifactid> <version>0.9.1</version> </dependency>
jwtutils.java(生成、解析token的工具类)
public class jwtutil { /** * 生成token * @param secretkey * @param ttlmillis * @param claims * @return */ public static string createtoken(string secretkey, long ttlmillis, map<string, object> claims) { // 指定签名的时候使用的签名算法,也就是header那部分 signaturealgorithm signaturealgorithm = signaturealgorithm.hs256; // 生成token的过期时间 long expmillis = system.currenttimemillis() + ttlmillis; date exp = new date(expmillis); // 设置jwt的body jwtbuilder builder = jwts.builder() // 如果有私有声明,一定要先设置这个自己创建的私有的声明,这个是给builder的claim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明的 .setclaims(claims) // 设置签名使用的签名算法和签名使用的秘钥 .signwith(signaturealgorithm, secretkey.getbytes(standardcharsets.utf_8)) // 设置过期时间 .setexpiration(exp); return builder.compact(); } /** * 解析token * @param secretkey * @param token * @return */ public static claims parsetoken(string secretkey, string token) { // 得到defaultjwtparser claims claims = jwts.parser() // 设置签名的秘钥 .setsigningkey(secretkey.getbytes(standardcharsets.utf_8)) // 设置需要解析的jwt .parseclaimsjws(token).getbody(); return claims; } }
jwt配置:
application.yaml:
user: jwt: # 设置jwt签名加密时使用的秘钥 user-secret-key: xxx # 设置jwt过期时间 user-ttl: 7200000 # 设置前端传递过来的令牌名称 user-token-name: token
jwtproperties:
@component @configurationproperties(prefix = "user.jwt") @data public class jwtproperties { private string usersecretkey; private long userttl; private string usertokenname; }
jwtclaimsconstant(管理常量):
public class jwtclaimsconstant { public static final string user_id = "userid"; }
jwt拦截器:
@component @slf4j public class jwtinterceptor implements handlerinterceptor { @resource private jwtproperties jwtproperties; @override public boolean prehandle(httpservletrequest request, httpservletresponse response, object handler) throws exception { //1. 获取用户信息 string token = request.getheader(jwtproperties.getusertokenname()); //2. 判断用户信息是否有效,存入threadlocal try { claims claims = jwtutil.parsetoken(jwtproperties.getusersecretkey(), token); string userinfo = claims.get(jwtclaimsconstant.user_id).tostring(); if (strutil.isnotblank(userinfo)){ usercontext.setuser(long.valueof(userinfo)); } //3. 放行 return true; }catch (exception e){ //4. 不通过 response.setstatus(401); return false; } } @override public void aftercompletion(httpservletrequest request, httpservletresponse response, object handler, exception ex) throws exception { //清除用户信息 usercontext.removeuser(); } }
webmvc配置(添加jwt拦截器)
@configuration public class webconfig implements webmvcconfigurer { @resource private jwtinterceptor jwtinterceptor; @override public void addinterceptors(interceptorregistry registry) { registry.addinterceptor(jwtinterceptor) .addpathpatterns("/user/**") .excludepathpatterns("/user/user/login"); } }
usercontext(存储用户登录信息,方便其他业务需求获取)
public class usercontext { private static final threadlocal<long> threadlocal = new threadlocal<>(); /** * 获取用户信息 * @return */ public static long getuser() { return threadlocal.get(); } /** * 设置用户信息 * @param userid */ public static void setuser(long userid){ threadlocal.set(userid); } /** * 移除用户信息 */ public static void removeuser(){ threadlocal.remove(); } }
登录业务逻辑:
controller层:
@restcontroller @requestmapping("/user/user") @slf4j public class usercontroller { @resource private userservice userservice; @postmapping("/login") public userloginvo login(@requestbody userlogindto userlogindto){ log.info("用户登录:{}",userlogindto); return userservice.login(userlogindto); } }
service层:
public interface userservice { userloginvo login(userlogindto userlogindto); }
@service @slf4j public class userserviceimpl implements userservice { @resource private usermapper usermapper; @resource private jwtproperties jwtproperties; @override public userloginvo login(userlogindto userlogindto) { string username = userlogindto.getusername(); string password = userlogindto.getpassword(); //1. 校验用户名和密码 userlogin userlogin = usermapper.getuserbyname(username); if (userlogin == null){ throw new baseexception("用户名或密码错误"); } password = digestutils.md5digestashex(password.getbytes()); if (!password.equals(userlogin.getpassword())){ throw new baseexception("用户名或密码错误"); } //2. 生成token hashmap<string, object> claims = new hashmap<>(); claims.put(jwtclaimsconstant.user_id, userlogin.getid()); string token = jwtutil.createtoken( jwtproperties.getusersecretkey(), jwtproperties.getuserttl(), claims); //3. 封装vo userloginvo loginvo = userloginvo.builder() .token(token) .userid(userlogin.getid()) .username(userlogin.getusername()) .build(); return loginvo; } }
mapper层:
@mapper public interface usermapper { userlogin getuserbyname(string username); }
<?xml version="1.0" encoding="utf-8" ?> <!doctype mapper public "-//mybatis.org//dtd mapper 3.0//en" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.sky.user.mapper.usermapper"> <select id="getuserbyname" resulttype="com.sky.user.pojo.entity.userlogin"> select * from user_login where username = #{username} and is_delete = 0; </select> </mapper>
其他关联代码:
@data @allargsconstructor @noargsconstructor public class userlogindto { /** * 用户名 */ private string username; /** * 密码 */ private string password; }
@data @builder @noargsconstructor @allargsconstructor public class userloginvo { private string token; private long userid; private string username; }
测试:
登录接口:
其他接口:
到此这篇关于java实现jwt登录认证的示例代码的文章就介绍到这了,更多相关java jwt登录认证内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论