shiro和jwt的区别
整合之前需要清楚shiro和jwt的区别。
首先shiro是一套安全认证框架,已经有了对token的相关封装。而jwt只是一种生成token的机制,需要我们自己编写相关的生成逻辑。
其次shiro可以对权限进行管理,jwt在权限这部分也只能封装到token中
1、引入依赖
org.apache.shiro
shiro-spring-boot-starter
1.5.3
com.auth0
java-jwt
3.4.0
和shiro相关:shiroconfig、jwtfilter、myrealm
2、jwtutil
jwt的自定义工具类,主要功能如下:
生成符合jwt机制的token字符串
可以对token字符串进行校验
获取token中的用户信息
判断token是否过期
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;
import lombok.extern.slf4j.slf4j;
import java.util.date;
/**
@author: lhy
jwt工具,用来生成、校验token以及提取token中的信息
*/
@slf4j
public class jwtutil {
//指定一个token过期时间(毫秒)
private static final long expire_time = 7 * 24 * 60 * 60 * 1000; //7天
/**
生成token
*/
//注意这里的sercet不是密码,而是进行三件套(salt md5 1024hash)处理密码后得到的凭证
//这里为什么要这么做,在controller中进行说明
public static string getjwttoken(string username, string secret) {
date date = new date(system.currenttimemillis() expire_time);
algorithm algorithm = algorithm.hmac256(secret); //使用密钥进行哈希
// 附带username信息的token
return jwt.create()
.withclaim(“username”, username)
.withexpiresat(date) //过期时间
.sign(algorithm); //签名算法
}
/**
校验token是否正确
*/
public static boolean verifytoken(string token, string username, string secret) {
try {
//根据密钥生成jwt效验器
algorithm algorithm = algorithm.hmac256(secret);
jwtverifier verifier = jwt.require(algorithm)
.withclaim(“username”, username)
.build();
//效验token(其实也就是比较两个token是否相同)
decodedjwt jwt = verifier.verify(token);
return true;
} catch (exception exception) {
return false;
}
}
/**
在token中获取到username信息
*/
public static string getusername(string token) {
try {
decodedjwt jwt = jwt.decode(token);
return jwt.getclaim(“username”).asstring();
} catch (jwtdecodeexception e) {
return null;
}
}
public static boolean isexpire(string token){
decodedjwt jwt = jwt.decode(token);
return jwt.getexpiresat().gettime() < system.currenttimemillis() ;
}
}
3、jwttoken
public class jwttoken implements authenticationtoken {
private string token;
public jwttoken(string token) {
this.token = token;
}
@override
public object getprincipal() {
return token;
}
@override
public object getcredentials() {
return token;
}
}
6、myrealm
realm可以说是shiro两大功能:认证和授权的入口。可以自定义realm,对认证的方式进行自定义处理。重心先放在认证方法上,只要调用了subject.login(token)方法,就会进入到realm的dogetauthenticationinfo内
public class myrealm extends authorizingrealm {
@autowired
private userservice userservice;
/**
* 限定这个realm只能处理jwttoken(不加的话会报错)
*/
@override
public boolean supports(authenticationtoken token) {
return token instanceof jwttoken;
}
/**
* 授权(授权部分这里就省略了,先把重心放在认证上)
*/
@override
protected authorizationinfo dogetauthorizationinfo(principalcollection principals) {
//获取到用户名,查询用户权限
return null;
}
/**
* 认证
*/
@override
protected authenticationinfo dogetauthenticationinfo(authenticationtoken auth) {
string token = (string) auth.getcredentials(); //jwttoken中重写了这个方法了
string username = jwtutil.getusername(token); // 获得username
//用户不存在(这个在登录时不会进入,只有在token校验时才有可能进入)
if(username == null)
throw new unknownaccountexception();
//根据用户名,查询数据库获取到正确的用户信息
user user = userservice.getuserinfobyname(username);
//用户不存在(这个在登录时不会进入,只有在token校验时才有可能进入)
if(user == null)
throw new unknownaccountexception();
//密码错误(这里获取到password,就是3件套处理后的保存到数据库中的凭证,作为密钥)
if (! jwtutil.verifytoken(token, username, user.getpassword())) {
throw new incorrectcredentialsexception();
}
//toke过期
if(jwtutil.isexpire(token)){
throw new expiredcredentialsexception();
}
return new simpleauthenticationinfo(user, token, getname());
}
}
5、jwtfilter
/**
* @author: lhy
* jwt过滤器,作为shiro的过滤器,对请求进行拦截并处理
跨域配置不在这里配了,我在另外的配置类进行配置了,这里把重心放在验证上
*/
@slf4j
@component
public class jwtfilter extends basichttpauthenticationfilter{
/**
* 进行token的验证
*/
@override
protected boolean executelogin(servletrequest request, servletresponse response) throws exception {
//在请求头中获取token
httpservletrequest httpservletrequest = (httpservletrequest) request;
string token = httpservletrequest.getheader("authorization"); //前端命名authorization
//token不存在
if(token == null || "".equals(token)){
resulttemplate