shiro jwt实现认证功能 -凯发k8国际

`

shiro jwt实现认证功能

    博客分类:
  • web
web 
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
网站地图