当前位置: 首页 > news >正文

六安住房和城乡建设部网站专业找工作网站下载

六安住房和城乡建设部网站,专业找工作网站下载,制作书签作文,食品包装设计公司目录用户认证功能的技术选型JWT和Session的区别基于JWT和Session的认证流程基于JWT的认证流程基于Session的认证流程基于JWT和Session的认证的优缺点基于JWT和Session的认证的安全性基于JWT和Session的认证的性能分析基于JWT的一次性和无法废弃基于JWT和Session的认证的续签选择…

目录

    • 用户认证功能的技术选型
    • JWT和Session的区别
    • 基于JWT和Session的认证流程
      • 基于JWT的认证流程
      • 基于Session的认证流程
    • 基于JWT和Session的认证的优缺点
    • 基于JWT和Session的认证的安全性
    • 基于JWT和Session的认证的性能分析
    • 基于JWT的一次性和无法废弃
    • 基于JWT和Session的认证的续签
    • 选择
    • JWT功能实现

用户认证功能的技术选型

  我们要实现用户的认证功能,很容易就想到使用JWT或者Session,但是我们在确定我们的技术选型之前,我们需要了解他们。
 
 

JWT和Session的区别

  基于JWT和Session的方式的主要区别就是用户状态的保存位置JWT是保存在客户端的,而Session是保存在服务端的
 
 

基于JWT和Session的认证流程

基于JWT的认证流程

1、用户在浏览器中输入用户名和密码,服务器通过密码校验之后生成一个token并保存到数据库,并将这个token返回给前端。
2、前端获取到token,将其存储到cookie或者local storage中,在后续的请求中都带着这个token信息进行访问。
3、服务器获取token值,通过查找数据判断当前的token是否有效。
 

基于Session的认证流程

1、用户在浏览器输入用户名和密码,服务器通过密码校验之后生成一个session保存到数据库。
2、服务器为用户生成一个sessionId,并将具有sessionId的cookie放置在用户浏览器中,在后续的请求中都带这个cookie信息进行访问。
3、服务器获取cookie,通过获取cookie中的sessionId查找数据库判断当前请求是否有效。

基于JWT和Session的认证的优缺点

  • JWT保存在客户端,在分布式环境下不需要做额外的工作。
  • Session保存在服务器,在分布式环境下需要实现多台机器共享Session,并且一般都需要结合Cookie实现认证,所以需要浏览器支持cookie,所以移动端无法使用session认证方案。

基于JWT和Session的认证的安全性

  • JWT是使用base64编码的,因此在JWT中不能存在敏感数据。如果在JWT中存储了敏感信息,可以解码出来是非常的不安全,比如用户的密码。
  • Session的信息是保存在服务器的,相对来说更安全。

基于JWT和Session的认证的性能分析

  • 经过编码之后的JWT是一个非常长的字符串,由于cookie的限制大小一般是4K,cookie很有可能放不下,所以JWT一般放在客户端的local storage里面。并且用户在系统中的每一次http请求请求都会把JWT携带在Header里面,HTTP请求的Header可能比Body还有大。
  • SessionId只是很短的一个字符串,所以JWT的HTTP请求比使用Session的开销大很多。

基于JWT的一次性和无法废弃

JWT是一次性的,想要修改里面的内容,只能重新生成一个JWT。
生成的一个JWT,在到过期之后就会始终有效,无法中途废弃。如果想中途废弃,一种常用的处理手段就是结合redis。

基于JWT和Session的认证的续签

Session的有效时间一般是30分钟,如果在30分钟内有访问,有效期会被刷新致30分钟。
而如果我们要改变JWT的有效时间,有两种方式:
1、最简单的一种方式是每次请求刷新JWT,即每个HTTP请求都返回一个新的JWT。这个方法不仅暴力不优雅,而且每次请求都要做JWT的加密解密,会带来性能问题。
2、我们可以在Redis中单独为每个JWT设置过期时间,每次访问的时候刷新JWT的过期时间。

 
 

选择

我投JWT一票,JWT有很多缺点,但是JWT在分布式环境下不需要像Session一样额外实现多机数据共享,不需要额外的工作,使用JWT不香吗?且JWT一次性的缺点可以结合redis进行弥补。

JWT功能实现

JWT所需依赖

public class JWTUtil {private static final Logger logger = LoggerFactory.getLogger(JWTUtil.class);//私钥private static final String TOKEN_SECRET = "123456";/*** 生成token,自定义过期时间 毫秒** @param userTokenDTO* @return*/public static String generateToken(UserTokenDTO userTokenDTO) {try {// 私钥和加密算法Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);// 设置头部信息Map<String, Object> header = new HashMap<>(2);header.put("Type", "Jwt");header.put("alg", "HS256");return JWT.create().withHeader(header).withClaim("token", JSONObject.toJSONString(userTokenDTO))//.withExpiresAt(date).sign(algorithm);} catch (Exception e) {logger.error("generate token occur error, error is:{}", e);return null;}}/*** 检验token是否正确** @param token* @return*/public static UserTokenDTO parseToken(String token) {Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);JWTVerifier verifier = JWT.require(algorithm).build();DecodedJWT jwt = verifier.verify(token);String tokenInfo = jwt.getClaim("token").asString();return JSON.parseObject(tokenInfo, UserTokenDTO.class);}
}

说明:

  • 生成的token中不带有过期时间,token的过期时间由redis进行管理。
  • UserTokenDTO中不带有敏感信息,如password字段不会出现在token中。

Redis工具类

public final class RedisServiceImpl implements RedisService {/*** 过期时长*/private final Long DURATION = 1 * 24 * 60 * 60 * 1000L;@Resourceprivate RedisTemplate redisTemplate;private ValueOperations<String, String> valueOperations;@PostConstructpublic void init() {RedisSerializer redisSerializer = new StringRedisSerializer();redisTemplate.setKeySerializer(redisSerializer);redisTemplate.setValueSerializer(redisSerializer);redisTemplate.setHashKeySerializer(redisSerializer);redisTemplate.setHashValueSerializer(redisSerializer);valueOperations = redisTemplate.opsForValue();}@Overridepublic void set(String key, String value) {valueOperations.set(key, value, DURATION, TimeUnit.MILLISECONDS);log.info("key={}, value is: {} into redis cache", key, value);}@Overridepublic String get(String key) {String redisValue = valueOperations.get(key);log.info("get from redis, value is: {}", redisValue);return redisValue;}@Overridepublic boolean delete(String key) {boolean result = redisTemplate.delete(key);log.info("delete from redis, key is: {}", key);return result;}@Overridepublic Long getExpireTime(String key) {return valueOperations.getOperations().getExpire(key);}
}

业务实现

登陆功能

public String login(LoginUserVO loginUserVO) {//1.判断用户名密码是否正确UserPO userPO = userMapper.getByUsername(loginUserVO.getUsername());if (userPO == null) {throw new UserException(ErrorCodeEnum.TNP1001001);}if (!loginUserVO.getPassword().equals(userPO.getPassword())) {throw new UserException(ErrorCodeEnum.TNP1001002);}//2.用户名密码正确生成tokenUserTokenDTO userTokenDTO = new UserTokenDTO();PropertiesUtil.copyProperties(userTokenDTO, loginUserVO);userTokenDTO.setId(userPO.getId());userTokenDTO.setGmtCreate(System.currentTimeMillis());String token = JWTUtil.generateToken(userTokenDTO);//3.存入token至redisredisService.set(userPO.getId(), token);return token;
}

说明:

  • 判断用户名密码是否正确。
  • 用户名密码正确则生成token。
  • 将生成的token保存至redis。

登出功能

public boolean loginOut(String id) {boolean result = redisService.delete(id);if (!redisService.delete(id)) {throw new UserException(ErrorCodeEnum.TNP1001003);}return result;
}

将对应的key删除即可

更新密码功能

public String updatePassword(UpdatePasswordUserVO updatePasswordUserVO) {//1.修改密码UserPO userPO = UserPO.builder().password(updatePasswordUserVO.getPassword()).id(updatePasswordUserVO.getId()).build();UserPO user = userMapper.getById(updatePasswordUserVO.getId());if (user == null) {throw new UserException(ErrorCodeEnum.TNP1001001);}if (userMapper.updatePassword(userPO) != 1) {throw new UserException(ErrorCodeEnum.TNP1001005);}//2.生成新的tokenUserTokenDTO userTokenDTO = UserTokenDTO.builder().id(updatePasswordUserVO.getId()).username(user.getUsername()).gmtCreate(System.currentTimeMillis()).build();String token = JWTUtil.generateToken(userTokenDTO);//3.更新tokenredisService.set(user.getId(), token);return token;
}

说明:

  • 更新用户密码时需要重新生成新的token,并将新的token返回给前端,由前端更新保存在local storage中的token,同时更新存储在redis中的token,这样实现可以避免用户重新登陆,用户体验感不至于太差。

拦截器类

public boolean preHandle(HttpServletRequest request, HttpServletResponse response,Object handler) throws Exception {String authToken = request.getHeader("Authorization");String token = authToken.substring("Bearer".length() + 1).trim();UserTokenDTO userTokenDTO = JWTUtil.parseToken(token);//1.判断请求是否有效if (redisService.get(userTokenDTO.getId()) == null || !redisService.get(userTokenDTO.getId()).equals(token)) {return false;}//2.判断是否需要续期if (redisService.getExpireTime(userTokenDTO.getId()) < 1 * 60 * 30) {redisService.set(userTokenDTO.getId(), token);log.error("update token info, id is:{}, user info is:{}", userTokenDTO.getId(), token);}return true;
}

说明:拦截器中主要做两件事,一是对token进行校验,二是判断token是否需要进行续期

token校验:

  • 判断id对应的token是否不存在,不存在则token过期
  • 若token存在则比较token是否一致,保证同一时间只有一个用户操作

token自动续期:
为了不频繁操作redis,只有当离过期时间只有30分钟时才更新过期时间。

拦截器配置类

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(authenticateInterceptor()).excludePathPatterns("/logout/**").excludePathPatterns("/login/**").addPathPatterns("/**");}@Beanpublic AuthenticateInterceptor authenticateInterceptor() {return new AuthenticateInterceptor();}
}

  
  
  

http://www.yayakq.cn/news/979221/

相关文章:

  • 五屏网站建设怎样关于酒店网站建设的摘要
  • 盐城市城乡建设局网站学校网站建设运行情况
  • 毕业设计 旅游网站建设重庆网站推广营销
  • 湖南长沙益阳网站建设学校网站栏目建设
  • 做学校网站导航条应该有哪些wordpress 登录页美化
  • 建设个人技术网站学平面设计哪个学校好
  • 做网站后端如何接业务图文排版设计
  • 济宁网站建设服务seo零基础教学
  • 新网$网站优化科技型中小企业税收优惠政策2022
  • 不需要备案如何做网站网站建设人员的工资分配
  • 如何快速开发手机appseo怎么发外链的
  • 竞赛网站建设风险评估做照片的网站有哪些
  • 河南郑州创建网站公司烟台企业宣传片制作公司
  • 海口旅游类网站建设wordpress 微博相册
  • 一个域名怎么做多个网站网页版抖音入口
  • 网站开发研企业管理系统数据库
  • 淘宝客有必须做网站吗wordpress 备份云盘
  • 网站开发网上接单网站做虚假宣传有没有做处罚
  • 二级网站建设情况说明书凡客诚品还经营吗
  • 如何制作手机购物网站网站建设开
  • 怎么做福利视频网站电子政务网站开发
  • 大型网站制作小程序wordpress 插件 摘要
  • 北京市工程建设交易信息网站wordpress it博客主题
  • 上海袜网站建设成都尚舍设计公司
  • 漳州做网站配博大钱少a免费咨询劳动仲裁
  • 石家庄做手机网站推广天津市武清区网站建设
  • 玉器哪家网站做的好硬件开发工程师待遇
  • 做网站 先上线再调整安卓手机怎么制作网站
  • 做爰片姿势网站扬州住房和建设局网站
  • 网站开发开什么票电子商务网站开发案例