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());
            }
        }
    }
    
    
  • 相关阅读:
    csu1804
    uvalive4513
    poj3264(Sparse-Table 算法模板)
    uva11107(后缀数组)
    poj2774(最长公共子串)
    uvalive4108(线段树)
    hdu5306 Gorgeous Sequence
    bzoj2823: [AHOI2012]信号塔&&1336: [Balkan2002]Alien最小圆覆盖&&1337: 最小圆覆盖
    bzoj3330: [BeiJing2013]分数
    bzoj1283: 序列
  • 原文地址:https://www.cnblogs.com/variablex/p/14513580.html
Copyright © 2011-2022 走看看