使用Springboot基于拦截器和redis的Jwt判断用户登录以及安全校验
这里简单介绍用户登录解析Jwt token,从请求的session、以及redis中获取我们想要信息,再做具体业务操作。
不熟悉Jwt概念和用法的可以参考前面两篇:
- Jwt入门教程( 一) | 原理和用法.
- Jwt入门教程:实战( 二) | Java/.Net/Python中的使用.
看了前两篇,下面就不多说了,直接贴代码:(代码可能较长,因为附带了redis的配置,继续往下看。)
首先,准备工作:配置redis(下方redis的代码较长,大家斟酌,需要的可以copy,放在最后)
下面是正文的开始:
1.MVC配置拦截器
/**
* MVC配置
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private TokenInterceptor tokenInterceptor;//自定义Token拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(tokenInterceptor).addPathPatterns("/**");//token拦截
}
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*")
.allowedHeaders("Content-Type", "Authorization")
.allowCredentials(false)
.maxAge(3600);
}
}
2.拦截器方法:(这里使用了redis)
import com.huangtu.common.util.user.JwtUtilsHelper;
import com.huangtu.config.RedisUtilsTwo;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwt;
import io.jsonwebtoken.impl.Base64Codec;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author 慌途L
*/
@Component
public class TokenInterceptor extends HandlerInterceptorAdapter {
//注入redis工具类
@Autowired
private RedisUtilsTwo redisUtilsTwo;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
try {
String cookie = request.getHeader("cookie");
System.out.println(cookie + "\n");
/**
* accessToken=eyJhbGciOiJIUzUxMiIsImlhdCI6MTU0MzE5OTg4MywiZXhwIjoxNTQzMjE0MjgzfQ.eyJ1c2VyX2lkIjoxMDAxLCJ5c2VyX25hbWUiOiJhZG1pbiIsImlwIjoiMTkyLjE2OC4xMC4yMDMifQ.-qXmphVPtcmO3PLmuQIiFL7khhKiDjwPZvGyxLbyBOkIMdtFJ7whLY0hSabbJwYH9Dcxmhf1tdPKN2jGSP5YBQ; JSESSIONID=6A769332782C0F436510214757C16063
*/
//token最后还跟了sessionid,去除
String[] split1 = cookie.split(";");
/**
* accessToken=eyJhbGciOiJIUzUxMiIsImlhdCI6MTU0MzE5OTg4MywiZXhwIjoxNTQzMjE0MjgzfQ.eyJ1c2VyX2lkIjoxMDAxLCJ1c2VyX25hbWU5OiJhZG1pbiIsImlwIjoiMTkyLjE2OC4xMC4yMDMifQ.-qXmphVPtcmO3PLmuQIiFL7khhKiDjwPZvGyxLbyBOkIMdtFJ7whLY0hSabbJwYH9Dcxmhf1tdPKN2jGSP5YBQ
*/
//得到accessToken
String[] split = split1[0].split("=");
System.out.println("accessToken"+split[1]);
//验证token
String login = verificationToken(split[1]);
return true;
} catch (Exception e){
e.printStackTrace();
return false;
}
}
/**
* 验证token
*
* @return
*/
public String verificationToken(String jwt) {
String[] splitJwt = jwt.split("\\.");
String params = "";
if (splitJwt.length == 3) {
//从redis里面拿到当前用户的accessToken进行对比
String accessToken = redisUtilsTwo.get("accessToken");
if(StringUtils.isNotBlank(accessToken)){
if(jwt.equals(accessToken)){
System.out.println("token验证通过");
String header = splitJwt[0];
String payload = splitJwt[1];
String signature = splitJwt[2];//带过来的签名
System.out.println(Base64Codec.BASE64URL.decodeToString(header));
System.out.println(Base64Codec.BASE64URL.decodeToString(payload));
//得到user数据--jwt的payload
Claims claims = JwtUtilsHelper.accessTonkenDecodePart(jwt);
if (!claims.isEmpty() && claims.size()>0) {
Jwt jwt1 = JwtUtilsHelper.accessTonkenDecodeAll(jwt);
JSONObject jsonObject = JSONObject.fromObject(jwt1.getHeader());
long iat = Integer.parseInt(jsonObject.get("iat").toString());
long exp = Integer.parseInt(jsonObject.get("exp").toString());
//登录时间和过期时间
System.out.println(iat+"||||"+exp);
if (!JwtUtilsHelper.isTokenExpired(exp)) {//判断token有效性
String userId = claims.get("user_id").toString();
String userName = claims.get("user_name").toString();
String ip = claims.get("ip").toString();
System.out.println("userId="+userId);
System.out.println("userName="+userName);
System.out.println("ip="+ip);
if ("169061".equals(userId) && "admin".equals(userName) && "192.168.110.555".equals(ip)) {
params = "token有效";//校验成功,数据完全一致
} else {
params = "用户id或用户名或ip地址有误";
}
} else {
params = "token过期";
}
} else {
params = "token的payload无数据";
}
} else {
params = "token被篡改";
}
} else{
params = "用户为登录";
}
} else {
params = "Jwt Token格式错误";
}
return params;
}
}
3.使用Postman请求:(用的是我项目的请求格式,大家随意),这里我放在请求头里面:使用名字cookie
4.到这里,基本上就结束了,大家可以在拦截器里面debugger一步步走。
配置文件:
spring:
redis:
database: 0
host: localhost
port: 6379
password: 123456 # 密码()
timeout: 6000 # 连接超时时长(毫秒)
pool:
max-active: 1000 # 连接池最大连接数(使用负值表示没有限制)
max-wait: -1 # 连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 10 # 连接池中的最大空闲连接
min-idle: 5 # 连接池中的最小空闲连接
cache:
type: none
JedisPool:
/**
* @author 慌途L
*/
@Configuration
@EnableCaching
public class RedisConfigTwo extends CachingConfigurerSupport {
private Logger logger = Logger.getLogger(getClass());
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.timeout}")
private int timeout;
@Value("${spring.redis.pool.max-idle}")
private int maxIdle;
@Value("${spring.redis.pool.max-wait}")
private long maxWaitMillis;
@Value("${spring.redis.password}")
private String password;
@Value("${spring.redis.database}")
private int dataBase;
@Bean
public JedisPool redisPoolFactory() {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(maxIdle);
jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port, timeout, password,dataBase);
return jedisPool;
}
}
redis工具类:
import org.springframework.stereotype.Component;
import redis.clients.jedis.BinaryClient;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author 慌途L
*/
@Component
public class RedisUtilsTwo{
@Resource
private JedisPool jedisPool;
/**
* 获取数据
* @param key
* @return
*/
public String get(String key){
String value=null;
Jedis jedis=null;
try{
jedis=jedisPool.getResource();
value=jedis.get(key);
}catch (Exception e){
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
}finally {
close(jedis);
}
return value;
}
public void del(String key) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
jedis.del(key);
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
close(jedis);
}
}
public void set(String key, String value) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
jedis.set(key, value);
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
close(jedis);
}
}
public void set(String key, String value, int time) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
jedis.set(key, value);
jedis.expire(key, time);
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
close(jedis);
}
}
public void hset(String key, String field, String value) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
jedis.hset(key, field, value);
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
close(jedis);
}
}
/**
* 获取数据
*
* @param key
* @return
*/
public String hget(String key, String field) {
String value = null;
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
value = jedis.hget(key, field);
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
close(jedis);
}
return value;
}
public void hdel(String key, String field) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
jedis.hdel(key, field);
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
close(jedis);
}
}
/**
* 存储REDIS队列 顺序存储
* @param key reids键名
* @param value 键值
*/
public void lpush(String key, String value) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
jedis.lpush(key, value);
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
close(jedis);
}
}
/**
* 移除队列中出现第一个数据
* @param key
* @param value
* @return
*/
public long lrem(String key, String value){
Jedis jedis = null;
long l =0 ;
try{
jedis = jedisPool.getResource();
l = jedis.lrem(key,1,value);
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
close(jedis);
}
return l;
}
/**
* 存储REDIS队列 反向存储
* @param key reids键名
* @param value 键值
*/
public long rpush(String key, String value) {
Jedis jedis = null;
long flage=0;
try {
jedis = jedisPool.getResource();
flage = jedis.rpush(key, value);
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
close(jedis);
}
return flage;
}
/**
* 存储REDIS队列 反向存储
* @param key reids键名
* @param value 键值
*/
public long rpush(String key, String value,int seconds) {
Jedis jedis = null;
long flage=0;
try {
jedis = jedisPool.getResource();
flage = jedis.rpush(key, value);
jedis.expire(key, seconds);
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
close(jedis);
}
return flage;
}
/**
* 在列表的元素前或者后插入元素,返回List的长度
* @param key
* @param where LIST_POSITION LIST_POSITION.BEFORE之前添加;LIST_POSITION.AFTER之后添加
* @param pivot 以该元素作为参照物,是在它之前,还是之后
* @param value
* @return Long
*/
public long linsert(String key, BinaryClient.LIST_POSITION where, String pivot, String value){
Jedis jedis = null;
long flage=0;
try {
jedis = jedisPool.getResource();
flage = jedis.linsert(key, where, pivot, value);
} catch (Exception e) {
flage = -1;
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
close(jedis);
}
return flage;
}
/**
* 将一个或多个值插入到已存在的列表头部,当成功时,返回List的长度;当不成功(即key不存在时,返回0)
* @param key
* @param value String
* @return Long
*/
public long lpushx(String key, String value){
Jedis jedis = null;
long flage=0;
try {
jedis = jedisPool.getResource();
flage = jedis.lpushx(key, value);
} catch (Exception e) {
flage = -1;
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
close(jedis);
}
return flage;
}
/**
* 将列表 source 中的最后一个元素(尾元素)弹出,并返回给客户端
* @param key reids键名
* @param destination 键值
*/
public void rpoplpush(String key, String destination) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
jedis.rpoplpush(key, destination);
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
close(jedis);
}
}
/**
* 获取队列数据
* @param key 键名
* @return
*/
public List lpopList(String key) {
List list = null;
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
list = jedis.lrange(key, 0, -1);
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
close(jedis);
}
return list;
}
/**
* 获取队列数据,返回并删除列表的第一个(LPOP)或最后一个(RPOP)元素。
* @param key 键名
* @return
*/
public String rpop(String key) {
String bytes = null;
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
bytes = jedis.rpop(key);
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
close(jedis);
}
return bytes;
}
public void hmset(Object key, Map hash) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
jedis.hmset(key.toString(), hash);
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
close(jedis);
}
}
public void hmset(Object key, Map hash, int time) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
jedis.hmset(key.toString(), hash);
jedis.expire(key.toString(), time);
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
close(jedis);
}
}
public List hmget(Object key, String... fields) {
List result = null;
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
result = jedis.hmget(key.toString(), fields);
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
close(jedis);
}
return result;
}
public Set hkeys(String key) {
Set result = null;
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
result = jedis.hkeys(key);
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
close(jedis);
}
return result;
}
public List lrange(String key, int from, int to) {
List result = null;
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
result = jedis.lrange(key, from, to);
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
close(jedis);
}
return result;
}
public Map hgetAll(String key) {
Map result = null;
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
result = jedis.hgetAll(key);
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
close(jedis);
}
return result;
}
public long llen(String key) {
long len = 0;
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
jedis.llen(key);
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
close(jedis);
}
return len;
}
/**
* 修改list中指定位置的值
* @param key
* @param index
* @param value
* @return 正确返回ok
*/
public String lset(String key,long index,String value){
Jedis jedis = null;
String s = null;
try {
jedis = jedisPool.getResource();
s = jedis.lset(key,index,value);
} catch (Exception e) {
//释放redis对象
jedisPool.returnBrokenResource(jedis);
e.printStackTrace();
} finally {
//返还到连接池
close(jedis);
}
return s;
}
private void close(Jedis jedis) {
try{
jedisPool.returnResource(jedis);
}catch (Exception e){
if(jedis.isConnected()){
jedis.quit();
jedis.disconnect();
}
}
}
}
结语:目前使用的就是这些啦,希望对大家有所帮助。后续会有在shiro中的使用,敬请期待!