zoukankan      html  css  js  c++  java
  • SpringBoot-整合Shiro和JWT时关于JWT部分的内容

    本文提供一个SpringBoot中整合和shiro和JWT时,JWT的模板。

    关于JWT(Json web token)的知识可以参考如下博客:
    https://www.jianshu.com/p/576dbf44b2ae
    https://zhuanlan.zhihu.com/p/86937325

    SpringBoot中整合和shiro和JWT时,关于JWT的部分有三个类需要编写:

    JWTToken: 实现AuthenticationToken
    JWTUtils: 工具类,用于token的生成,验证,以及获取token中的一些信息
    JWTFilter: 过滤器,判断请求中是否携带token,以便确定是否需要提交realm登录

    1、JWTToken

    import org.apache.shiro.authc.AuthenticationToken;
    
    public class JWTToken implements AuthenticationToken {
    
        private String token;
    
        public JWTToken(String token) {
            this.token = token;
        }
        //getPrincipal()方法返回的是帐号,getCredentials()返回的是密码
        //在这里的实现里面全部都返回token
    
        @Override
        public Object getPrincipal() {
            return token;
        }
    
        @Override
        public Object getCredentials() {
            return token;
        }
    }
    

    JWTToken实现AuthenticationToken的原因是在Shiro的Realm的doGetAuthenticationInfo(AuthenticationToken authenticationToken)方法中传入的是AuthenticationToken.

    2、JWTUtils

    该工具类在其他地方会被使用,比如在用户第一次登录时用sign方法生成token。以及用户已经登陆后,验证用户发送的token是否正确,可以用verify方法。

    import com.auth0.jwt.JWT;
    import com.auth0.jwt.JWTVerifier;
    import com.auth0.jwt.algorithms.Algorithm;
    import com.auth0.jwt.interfaces.DecodedJWT;
    import org.springframework.stereotype.Component;
    import java.util.Date;
    
    //JWTUtils:用来生成token,校验token,从token中获取登录名
    @Component
    public class JWTUtils {
    
        private static final long EXPIRE_TIME = 7 * 24 * 60 * 60 * 1000;
    
        //生成token
        public static String sign(long userid,String password){
            try{
                Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
                Algorithm algorithm = Algorithm.HMAC256(password);//用password作为secret,当然这个password要用MD5加密后的
                return JWT.create()
                        .withClaim("userid", userid)//将userid信息保存到token中
                        .withExpiresAt(date) //设置过期token过期时间
                        .sign(algorithm); // 加密
            }catch(Exception e){
                return null;
            }
        }
    
        //校验token
        public static boolean verify(String token, long userid, String password){
            try {
                Algorithm algorithm = Algorithm.HMAC256(password);
                JWTVerifier jwtVerifier = JWT.require(algorithm)
                        .withClaim("userid", userid).build();
                DecodedJWT decodedJWT = jwtVerifier.verify(token);
                return true;
            } catch (Exception e){
                return false;
            }
        }
    
        //从token中获取用户名
        public long getUserId(String token){
            if(token == null || "".equals(token)){
                return -1;
            }
            try {
                DecodedJWT jwt = JWT.decode(token); //解码token
                return jwt.getClaim("userid").asLong(); //获取token保存的userid信息
            } catch(Exception e){
                return -1;
            }
        }
    }
    

    3、JWTFilter

    继承shiro中的BasicHttpAuthenticationFilter,该类会在ShiroConfig中被添加到filter中,以后每个请求都会经过JWTFilter中的isAccessAllowed方法

    import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
    import org.springframework.stereotype.Component;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.net.URLEncoder;
    
    @Component
    public class JWTFilter extends BasicHttpAuthenticationFilter  {
        @Override
        protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object mappedValue) {
            HttpServletRequest request = (HttpServletRequest) servletRequest;
            String token = request.getHeader("token"); //从前端传过来的request中取token
            if(token != null){ //判断用户是不是需要登录,如果token不为空表示需要登录
                try{
                    //应该在这里判断token是否过期
                    executeLogin(request, servletResponse);
                    return true;
                }catch(Exception e){
                    responseError(servletResponse, e.getMessage());
                }
            }
            //如果请求头不存在 Token,可能是游客状态访问或者一些不需要登陆就能访问的请求,无需检查 token,直接返回 true
            return true;
        }
    
    
        @Override
        protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
            HttpServletRequest httpServletRequest = (HttpServletRequest) request;
            String token = httpServletRequest.getHeader("token");
            JWTToken jwtToken = new JWTToken(token);
            // 提交给realm进行登入,如果错误他会抛出异常并被捕获
            getSubject(request, response).login(jwtToken);
            // 如果没有抛出异常则代表登入成功,返回true
            return true;
        }
    
        /**
         * 将非法请求跳转到 /unauthorized/**
         */
        private void responseError(ServletResponse response, String message) {
            try {
                HttpServletResponse httpServletResponse = (HttpServletResponse) response;
                //设置编码,否则中文字符在重定向时会变为空字符串
                message = URLEncoder.encode(message, "UTF-8");
                httpServletResponse.sendRedirect("/unauthorized/" + message);
            } catch (IOException e) {
                System.out.println(e.getMessage());
            }
        }
    }
    
    
  • 相关阅读:
    CentOS虚拟机和物理机共享文件夹实现
    集训第六周 数学概念与方法 概率 数论 最大公约数 G题
    集训第六周 数学概念与方法 概率 F题
    集训第六周 E题
    集训第六周 古典概型 期望 D题 Discovering Gold 期望
    集训第六周 古典概型 期望 C题
    集训第六周 数学概念与方法 UVA 11181 条件概率
    集训第六周 数学概念与方法 UVA 11722 几何概型
    DAG模型(矩形嵌套)
    集训第五周 动态规划 K题 背包
  • 原文地址:https://www.cnblogs.com/variablex/p/14513580.html
Copyright © 2011-2022 走看看