session、cookie及token对比

权限验证实现方式

  1. session
    1.实现方案:session+filter
    2.实现过程:URL/*->filter->通过URL判断是否是登录页,是,则放行。->不是,判断session中是否存在用户->不存在,则重定向到登录页;存在,放行->退出,注销session。

  2. cookie
    1.实现方案:session+filter
    2.实现过程:和session一样

  3. token
    1.实现方案:token+拦截器
    2.实现过程:URL/*->过滤器(可以自定义两个注解,一个放行注解,一个需要token验证注解)->是登录页,验证登录是否成功->否,重新登录;是,则生成token->传回给前段,可以使用cookie或响应头中->不是登录页,从请求头中获取token->token不存在,重新登录;token存在但过期,重新登录;token存在且不过去且正确->放行
    3.token验证方案:1.后端将生成的token放在Redis中,下次取出比较;2.jwt方式做签名认证,比较签名是否被修改即可,token是否超时
    4.token在请求时的存放地方:1.作为传入参数;2.放在cookie中;3.放在请求头中,也是最常见的

  4. 超时比较
    1.session超时(一段时间内无操作)后,退出。 session.setMaxInactiveInterval(60);
    2.cookie超时后也会退出。cookie.setMaxAge(300);res.addCookie(cookie);
    3.session超时,如3min,则指的是3min内无任何操作,就认为超时会退出;如果任意3min内一直有操作,则永不超时退出。如果浏览器关闭,则session生命周期结束,相当于退出了。
    4.cookie超时,如3min,则指的是session创建后,生产cookie的那一刻起,过了3min后cookie就超时了。
    5.如果要实现关闭浏览器后在访问页面,仍不用登录即可直接访问,需用到cookie。但cookie时间设置不当,会出现,正在访问页面,突然退出,要重新登录才行。如果从这个角度出发,当cookie和session都存在时候,cookie的超时时间应该设置无限大。
    6.如果cookie没有设置超时时间,其生命周期和会话周期绑定,存在浏览器内存中。浏览器关闭,cookie就消失。如果设置超时时间,则存在硬盘上。

  5. token实现方案具体代码

拦截器代码

@Component
public class AuthInterceptor implements HandlerInterceptor {

    @Autowired
    TokenUtil tokenUtil;
    public static final String SECRET = "123456";
    private static final Logger logger = LoggerFactory.getLogger(AuthInterceptor.class);

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {

    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        // 如果不是映射到方法直接通过
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }

        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        // 检查是否有passtoken注释,有则跳过认证
        if (method.isAnnotationPresent(PassToken.class)) {
            PassToken passToken = method.getAnnotation(PassToken.class);
            if (passToken.required()) {
                return true;
            }
        }

        // 检查有没有需要用户权限的注解
        if (method.isAnnotationPresent(UserLoginToken.class)) {
            UserLoginToken userLoginToken = method.getAnnotation(UserLoginToken.class);
            if (userLoginToken.required()) {
                String token = request.getHeader("token");
                Result result = new Result(ResultEnum.TOKEN_TIMEOUT_OR_WRONG);
                // 没有token
                if (StringUtils.isEmpty(token)) {
                    result.setMsg("no token,need login");
                    response.getWriter().print(JSON.toJSONString(result));
                    logger.error("no token,need login");
                    return false;
                }

                // 判断token是否过期,是否正确
                DecodedJWT jwt = null;
                try {
                    JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
                    jwt = verifier.verify(token);
                } catch (TokenExpiredException e) {
                    logger.error("token超时:");
                    result.setMsg("token is out time");
                    response.getWriter().print(JSON.toJSONString(result));
                    return false;
                } catch (SignatureVerificationException e) {
                    logger.error("token签名异常:");
                    result.setMsg("token is wrong");
                    response.getWriter().print(JSON.toJSONString(result));
                    return false;
                }
                int userid = jwt.getClaims().get("userId").asInt();
                request.setAttribute("userid", userid);
            }
        }

//        String urlPath = request.getRequestURI();
//        System.out.println("urlPath:," + urlPath);
//        if (!urlPath.contains("login")) {
//            String token = request.getHeader("token");
//            Result result = new Result(ResultEnum.FAILED);
//            if (StringUtils.isEmpty(token)) {
//                result.setMsg("no token,need login");
//                response.getWriter().print(JSON.toJSONString(result));
//                logger.error("no token,need login");
//                return false;
//            } else {
//                DecodedJWT jwt = null;
//                try {
//                    JWTVerifier verifier = JWT.require(Algorithm.HMAC256("qxmz")).build();
//                    jwt = verifier.verify(token);
//                } catch (TokenExpiredException e) {
//                    logger.error("token超时:");
//                    result.setMsg("token is out time");
//                    response.getWriter().print(JSON.toJSONString(result));
//                    return false;
//                } catch (SignatureVerificationException e) {
//                    logger.error("token签名异常:");
//                    result.setMsg("token is wrong");
//                    response.getWriter().print(JSON.toJSONString(result));
//                    return false;
//                }
//                int userid = jwt.getClaims().get("userId").asInt();
//                request.setAttribute("userid", userid);
//                System.out.println("userId:" + userid);
//            }
//        }
        return true;
    }
}

token工具类代码

@Component
public class TokenUtil {

    @Value("${token.expire_time}")
    private long EXPIRE_TIME;
    public static final String SECRET = "123456";
    private static final Logger logger = LoggerFactory.getLogger(TokenUtil.class);

    /**
     * 创建token
     * 
     * @author junzhang19
     * @since 2020年7月24日下午2:00:45
     * @param userId
     * @return
     */
    public String creatToken(int userId) {
        String token = null;
        Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME * 1000);
        try {
            Algorithm algorithm = Algorithm.HMAC256(SECRET);
            // 附带userId信息
            token = JWT.create().withClaim("userId", userId).withExpiresAt(date).sign(algorithm);
        } catch (JWTCreationException e) {
            // 如果Claim不能转换为JSON,或者在签名过程中使用的密钥无效,那么将会抛出JWTCreationException异常。
            logger.error("token创建异常:{}", e);
        }
        return token;
    }

    public DecodedJWT verifyToken(String token) {
        DecodedJWT jwt = null;
        try {
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
            jwt = verifier.verify(token);
        } catch (TokenExpiredException e) {
            logger.error("token超时:{}", e);
        } catch (SignatureVerificationException e) {
            logger.error("token签名异常:{}", e);
        }
        return jwt;
    }

}

需要token及放行,对应的两个注解

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface UserLoginToken {

    boolean required() default true;
}
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PassToken {

    boolean required() default true;
}

参考文档:
https://www.jianshu.com/p/e88d3f8151db
https://www.jianshu.com/p/0fed399c2561

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值