使用jwt进行token认证
简单说明:最近在搞权限这一块的东西,需要用到jwt进行token认证,才有了如下的demo演示 具体细节可以看gitbug,噗,不是bug是hub github地址:https://github.com/xuchao6969/jwt_demo 点击前边的gitbug也可以哦
项目是springboot+thymeleaf+mybatis+mysql搭建的
//pom核心依赖
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
//application.yml的核心配置
#token有效期 单位ms
expire_time: 9000000 #token加密secret
token_secret: jwtsecret
token的工具类,包括生成签名、校验、解析等方法
package com.xc.jwt_demo.util; import java.util.Date;
import java.util.HashMap;
import java.util.Map; import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT; public class JwtTokenUtil { /**
* 生成签名,过期时间可以从配置文件里读取 具体看方法调用处
* @param **username**
* @param **password**
* @return
*/
public static String sign(String username, String userId,Long expiretime,String secret) {
try {
// 设置过期时间
Date date = new Date(System.currentTimeMillis() + expiretime);
// 私钥和加密算法
Algorithm algorithm = Algorithm.HMAC256(secret);
// 设置头部信息
Map<String, Object> header = new HashMap<>(2);
header.put("Type", "Jwt");
header.put("alg", "HS256");
// 返回token字符串
return JWT.create()
.withHeader(header)
.withClaim("loginName", username)
.withClaim("userId", userId)
.withExpiresAt(date)
.sign(algorithm);
} catch (Exception e) {
e.printStackTrace();
return null;
}
} /**
* 检验token是否正确
* @param **token**
* @return
*/
public static boolean verify(String token,String secret){
try {
Algorithm algorithm = Algorithm.HMAC256(secret);
JWTVerifier verifier = JWT.require(algorithm).build();
@SuppressWarnings("unused")
DecodedJWT jwt = verifier.verify(token);
return true;
} catch (Exception e){
return false;
}
} /**
* 从token中获取username信息
* @param **token**
* @return
*/
public static String getUserName(String token){
try {
DecodedJWT jwt = JWT.decode(token);
return jwt.getClaim("loginName").asString();
} catch (JWTDecodeException e){
e.printStackTrace();
return null;
}
} /**
* token是否过期
* @param token
*/
public static Boolean checkExpire(String token) {
try {
DecodedJWT jwt = JWT.decode(token);
//获取token过期时间
Date expiretime = jwt.getExpiresAt();
String etStr = String.valueOf(expiretime.getTime());
//获取系统当前时间
String nowTime = String.valueOf(System.currentTimeMillis());
//如果系统当前时间超过token过期时间返回false
if(nowTime.compareTo(etStr)>0){
return false;
}
return true;
} catch (JWTDecodeException e){
e.printStackTrace();
}
return true;
} }
JwtTokenUtil.java
token拦截器,针对所有的请求进行token认证 也是核心
package com.xc.jwt_demo.interceptor; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor; import com.xc.jwt_demo.util.JwtTokenUtil; @Component
public class TokenInterceptor implements HandlerInterceptor {
private static final Logger logger = LoggerFactory.getLogger(TokenInterceptor.class); //从配置文件application.yml进行加载
@Value("${token_secret}")
private String secret; @Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object)
throws Exception {
String str = request.getMethod();
if (str.equals("OPTIONS")) {
response.setStatus(HttpServletResponse.SC_OK);
return true;
}
response.setCharacterEncoding("utf-8");
String token = request.getHeader("token");
if (null != token) {
//校验token是否过期
boolean result = JwtTokenUtil.verify(token, secret);
if (result) {
logger.info("通过拦截器");
return true;
}
}
logger.info("认证失败");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write("Token不存在或者已失效");
return false;
}
}
TokenInterceptor.java
token拦截器的配置,主要用来配置不需要拦截路径,比如登录...
package com.xc.jwt_demo.config; import java.util.ArrayList;
import java.util.List; import com.xc.jwt_demo.interceptor.TokenInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration
public class InterceptorConfig implements WebMvcConfigurer{ private TokenInterceptor tokenInterceptor; public InterceptorConfig(TokenInterceptor tokenInterceptor) {
this.tokenInterceptor = tokenInterceptor;
} @Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(tokenInterceptor)
//拦截所有的请求
.addPathPatterns("/**")
//放开请求
.excludePathPatterns("/sys/test","/sys/login","/sys/doLogin","/js/**");
} }
InterceptorConfig.java
好了,下边的一坨坨代码就是常规的三层业务了,可以参考看一下UserServiceImpl里的生成token 解析token的调用,其他没啥大的价值 另外 我的token是存放在数据库的
package com.xc.jwt_demo.controller; import java.io.IOException;
import java.util.Map; import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import com.xc.jwt_demo.entity.User;
import com.xc.jwt_demo.service.UserService;
import com.xc.jwt_demo.util.JsonUtil;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*; @Controller
@RequestMapping("/sys")
public class LoginController { @Resource
private UserService userService; //测试页面
@RequestMapping("/test")
public String testThymeleaf(ModelMap model) {
User user = new User();
user.setUsername("二叔");
user.setMobile("911");
model.addAttribute("user", user);
return "/viewTest";
} //登录页面
@RequestMapping("/login")
public String login(ModelMap model) {
return "/login";
} @RequestMapping(value = "/doLogin")
@ResponseBody
public Integer login(User user) {
Map<String, Object> resultMap = userService.login(user.getUsername(),user.getPassword());
Integer code = (Integer) resultMap.get("code");
return code;
} //使用postman或者restclient进行token测试
@RequestMapping("/tokenTest")
public void TokenTest(HttpServletRequest request,HttpServletResponse response) throws IOException {
String token = request.getHeader("token");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write("认证成功 Token是:"+token);
}
}
LoginController.java
package com.xc.jwt_demo.service; import java.util.Map; public interface UserService { Map<String, Object> login(String username, String password); }
UserService.java
package com.xc.jwt_demo.service.impl; import java.util.HashMap;
import java.util.Map; import com.xc.jwt_demo.dao.UserDao;
import com.xc.jwt_demo.entity.User;
import com.xc.jwt_demo.service.UserService;
import com.xc.jwt_demo.util.JwtTokenUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.beans.factory.annotation.Value; @Service("userService")
public class UserServiceImpl implements UserService { private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class); //从配置文件application.yml读取token有效期时间 单位ms
@Value("${expire_time}")
private Long expiretime; //读取加密的secret
@Value("${token_secret}")
private String secret; @Autowired
private UserDao dao; @Override
public Map<String, Object> login(String username,String password) {
Map<String, Object> map = new HashMap<>();
User userObj = dao.getUserByUserName(username);
//判断用户是否存在
if(null == userObj){
map.put("code", 0);//用户不存在
return map;
}
//判断密码是否正确
if(! password.equals(userObj.getPassword())){
map.put("code", -1);//密码错误
return map;
}
map.put("code", 1);//用户存在
String tokenObj = userObj.getToken();
//用户token不存在就创建token
if(null == tokenObj || "".equals(tokenObj)){
String token = JwtTokenUtil.sign(userObj.getUsername(),userObj.getUserId(),expiretime,secret);
logger.info("-----------创建token-------: "+ token);
Map<String, Object> paraMap = new HashMap<>();
paraMap.put("token", token);
paraMap.put("userId", userObj.getUserId());
dao.addToken2User(paraMap);
map.put("token", token);
}else{
//取出用户token
String token = userObj.getToken();
logger.info("------存在的token-----: "+ token);
//判断token是否过期 不过期返回,过期 新建token返回并插入数据库
if(JwtTokenUtil.checkExpire(token)){
logger.info("-------token存在且有效------: "+ token);
map.put("token", token);
}else{
String tokenStr = JwtTokenUtil.sign(userObj.getUsername(),userObj.getUserId(),expiretime,secret);
logger.info("------token重新生成-----: "+ tokenStr);
Map<String, Object> paraMap = new HashMap<>();
paraMap.put("token", tokenStr);
paraMap.put("userId", userObj.getUserId());
dao.addToken2User(paraMap);
map.put("token", tokenStr);
}
}
map.put("userId", userObj.getUserId());
map.put("username", userObj.getUsername());
return map;
} }
UserServiceImpl.java
package com.xc.jwt_demo.dao; import org.apache.ibatis.annotations.Mapper;
import com.xc.jwt_demo.entity.User;
import java.util.Map; @Mapper
public interface UserDao {
User getUserByUserName(String username); void addToken2User(Map<String, Object> map);
}
UserDao.java
package com.xc.jwt_demo.entity; import lombok.Data; @Data
public class User { private String userId;
private String username;
private String password;
private String email;
private String mobile;
private String status;
private String createBy;
private String createTime;
private String lastUpdateBy;
private String lastUpdateTime;
private String department;
private String realName;
private String establishVest;
private String delFlag;
private String token; }
User.java
<?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.xc.jwt_demo.dao.UserDao">
<resultMap id="UserResultMap" type ="com.xc.jwt_demo.entity.User">
<id property="userId" column="user_id" />
<result property="username" column="username" />
<result property="password" column="password" />
<result property="email" column="email" />
<result property="mobile" column="mobile" />
<result property="status" column="status" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="lastUpdateBy" column="last_update_by" />
<result property="lastUpdateTime" column="last_update_time" />
<result property="department" column="department" />
<result property="realName" column="real_name" />
<result property="establishVest" column="establish_vest" />
<result property="delFlag" column="del_flag" />
<result property="token" column="token" />
</resultMap> <sql id="tableName">t_user</sql> <update id="addToken2User" parameterType="java.util.Map">
update <include refid="tableName" /> set token = #{token} where user_id = #{userId}
</update> <select id="getUserByUserName" parameterType="String" resultMap="UserResultMap">
select * from <include refid="tableName" /> where username = #{username}
</select>
</mapper>
UserMapper.xml
另外说一点,很重要,在html页面中必须加入<link rel=“shortcut icon” href="#" /> 否则会在测试的时候会出现 favicon.ico不存在的问题,从而导致测试失败 vue的话也会有类似的问题
下边是测试
首先不带token访问tokenTest页面
后台打印
然后登陆 获取token
后台打印
然后 把token粘到postman或者restClient中 设置好header token再次访问
后台打印
最终结果
使用jwt进行token认证的更多相关文章
- token 与 基于JWT的Token认证
支持跨域访问,无状态认证 token特点 支持跨域访问: Cookie是不允许垮域访问的,这一点对Token机制是不存在的,前提是传输的用户认证信息通过HTTP头传输 无状态(也称:服务端可扩展行): ...
- 基于JWT的Token认证机制及安全问题
[干货分享]基于JWT的Token认证机制及安全问题 https://bbs.huaweicloud.com/blogs/06607ea7b53211e7b8317ca23e93a891
- iOS 开发之基于JWT的Token认证机制及解析
在移动端和服务端通信中,一般有两种认证方式:token 和 session. 1.session/cookie 认证机制: 在服务端创建一个Session对象,同时在客户端的浏览器端创建一个Cooki ...
- tp5.0使用JWT完成token认证技术
1.安装 composer require firebase/php-jwt 2.封装(在框架根目录extend下新建Token.php) 复制代码 <?php use Firebase\JWT ...
- Django+JWT实现Token认证
对外提供API不用django rest framework(DRF)就是旁门左道吗? 基于Token的鉴权机制越来越多的用在了项目中,尤其是对于纯后端只对外提供API没有web页面的项目,例如我们通 ...
- JWT实现token认证
演变 1.1 有状态服务 在原来的单体系统中,有状态服务,即服务端需要记录每次会话的客户端信息,从而识别客户端身份,根据用户身份进行请求的处理,session+cookie.在如今的大多数分布式系统中 ...
- 简单说说基于JWT的token认证方式
一.什么是认证 好多人不知道什么是认证,认证,其实就是服务端确认用户身份.Http协议是无状态的,客户端发送一条请求,服务端返回一条响应,二者就算做成一单买卖,一拍两散.在很久以前,互联网所能提供的服 ...
- 使用JWT实现Token认证
为什么使用JWT? 随着技术的发展,分布式web应用的普及,通过session管理用户登录状态成本越来越高,因此慢慢发展成为token的方式做登录身份校验,然后通过token去取redis中的缓存的用 ...
- 基于JWT的token认证机制
1. 一个JWT实际上就是一个字符串,由三部分组成 头部,载荷,签名 头部:事描述类型,签名,算法等 可以被表示成一个JSON对象 载荷:存放有效信息的地方 包含三个部分 (1)标准注册中的声明-建议 ...
随机推荐
- idea中Junit的使用
第一步:添加插件 添加插件:File->Settings->Plugins 第二步:修改设置 1.设置生成模式:File->Settings->Other Settings 指 ...
- java中整数的常量优化机制
java正常两个整数类型相加默认提升为int类型,如接受的类型比int小则会报错,当两个整数常量相加不超范围的情况下是不会报错 byte b = 3 +4: 条件:等号的右边必须全部都是整数常量才可以 ...
- python在循环中追加字典
1. 在循环中用append增加key值,最终生成全是key值的list: 2. 在循环中用append增加value值,最终生成全是value值的list: 3. 最后用zip将两个list合并成一 ...
- slow SQL
一.介绍 慢查询日志可用于查找需要很长时间才能执行的查询,因此是优化的候选者.但是,检查长慢的查询日志可能是一项耗时的任务. 二.配置 # 查看: slow_query_log 慢SQL开关 slow ...
- vue全家桶(2.6)
3.9.滚动行为 设置滚动行为的作用是导航到新路由时,让页面滚动到你想要的位置. const router = new VueRouter({ routes: [...], scrollBehavio ...
- 你还在担心rpc接口超时吗
在使用dubbo时,通常会遇到timeout这个属性,timeout属性的作用是:给某个服务调用设置超时时间,如果服务在设置的时间内未返回结果,则会抛出调用超时异常:TimeoutException, ...
- 给大家分享一下less的使用几个技巧
1.层级关系 让这个box范围内的全部包进来,这样的话就完美的进行调节,再也不用到处找第几行第几个,我刚才在哪个位置给覆盖了.一看便知! .box{ width: %; height: 300px; ...
- RocketMQ延迟消息的代码实战及原理分析
RocketMQ简介 RocketMQ是一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的.高可靠.万亿级容量.灵活可伸缩的消息发布与订阅服务. 它前身是MetaQ,是阿里基于Kafka ...
- day35 socket套接字介绍
目录 一.套接字发展史与分类 二.套接字工作流程 三.基于tcp的套接字 一.套接字发展史与分类 套接字起源于 20 世纪 70 年代加利福尼亚大学伯克利分校版本的 Unix,即人们所说的 BSD U ...
- Django之 Views组件
本节内容 路由系统 models模型 admin views视图 template模板 我们已经学过了基本的view写法 单纯返回字符串 1 2 3 4 5 6 7 8 def current_dat ...