Java打怪之路----谷粒商场认证服务

打印 上一主题 下一主题

主题 767|帖子 767|积分 2301

一、登录注册功能

1、登录短信验证码倒计时

2.登录短信验证码整合

注册功能写在认证服务中,用户前台点击获取验证码,需要远程调用第三方服务来执行短信验证码发送功能。 短信验证码主要使用阿里云短信验证码发送组件。用户前台点击获取验证码,向第三方服务发送请求,根据用户提供的手机号和验证码服务中配置的appcode等相关信息来请求阿里云验证码组件来发送验证码进行验证。
解决验证码防刷
验证码再次校验:将验证码存入redis中,
二、分布式Session

普通session共享存在的问题
2.1.Session的原理


  • 浏览器第一次访问服务器进行登录,服务器将用户信息保存到session中,该session存在服务器内存sessionManager中
  • 浏览器会让客户端保存一个jsessionid为指定值的cookie;
  • 客户端下次访问服务器,需要带上jsessionId为指定值的cookie,识别到用户登录信息
  • 浏览器关闭,清楚会话session;
  • 下次访问重复步骤1-4

2.2 存在的问题

在分布式项目中,不同微服务的服务器不同,同一服务也可能被负载均衡到不同的服务器。
域名不同,这样跨域名session无法统一
在auth.gulimall.com域名下,令牌的Domain在本域下,gulimall.com域无法获取到该数据

2.3解决办法

session复制:将session复制到每一个服务器中,可以保证服务器中的session都是相同的。

session客户端存储:将sesison存储在客户端

hash一致性:

使用redis存储session:

2.4SpringSession解决子域共享问题

引入依赖
  1.        
  2. <dependency>
  3.     <groupId>org.springframework.session</groupId>
  4.     <artifactId>spring-session-data-redis</artifactId>
  5. </dependency>
复制代码
配置文件中配置
  1. spring:
  2.   session:
  3.     store-type: redis
复制代码
主启动类中添加注解:@EnableRedisHttpSession
至此,可以保证session存入redis中。
然而,默认发的令牌。sessionid=abc的作用域是在当前域,需要解决子域session共享问题。
扩大子域范围
  1. @Configuration
  2. public class AchangmallSessionConfig {
  3.     @Bean
  4.     public CookieSerializer cookieSerializer() {
  5.         DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
  6.         //放大作用域
  7.         cookieSerializer.setDomainName("gulimall.com");
  8.         cookieSerializer.setCookieName("ACHANGSESSION");
  9.         return cookieSerializer;
  10.     }
  11.     @Bean
  12.     public RedisSerializer<Object> springSessionDefaultRedisSerializer() {//使用json存储redis,而不是默认的序列化存储
  13.         return new GenericJackson2JsonRedisSerializer();
  14.     }
  15. } Y
复制代码
原理
三、购物车

3.1ThreadLocal用户身份鉴别

用户身份鉴别流程:

  • 获取购物车之前首先要判断是否登录,需要整合springsession来共享数据
  • 第一次使用购物车功能,会给一个临时用户身份
    浏览器有一个cookie:use-key:标识用户身份,一个月后过期
    浏览器以后保存,每次访问都会带上这个cookie
    登录:session中有相关信息
    未登录:按照cookie中的user-key
    第一次使用:没有临时用户就要创建一个临时用户。
    这里采用拦截器来实现
具体实现:
拦截器配置

拦截器的注册:
  1. @Configuration
  2. public class    GulimallWebConfig implements WebMvcConfigurer {
  3.     @Override
  4.     public void addInterceptors(InterceptorRegistry registry) {
  5.         registry.addInterceptor(new CartInterceptor())//注册拦截器
  6.                 .addPathPatterns("/**");
  7.     }
  8. }
复制代码
购物车的拦截器实现spring中的HandlerInterceptor接口
  1. public class CartInterceptor implements HandlerInterceptor {
  2.     public static ThreadLocal<UserInfoTo> toThreadLocal = new ThreadLocal<>();
  3.     /***
  4.      * 目标方法执行之前
  5.      * @param request
  6.      * @param response
  7.      * @param handler
  8.      * @return
  9.      * @throws Exception
  10.      */
  11.     @Override
  12.     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  13.         UserInfoTo userInfoTo = new UserInfoTo();
  14.         HttpSession session = request.getSession();
  15.         //获得当前登录用户的信息
  16.         MemberResponseVo memberResponseVo = (MemberResponseVo) session.getAttribute(LOGIN_USER);
  17.         if (memberResponseVo != null) {
  18.             //用户登录了
  19.             userInfoTo.setUserId(memberResponseVo.getId());
  20.         }
  21.         Cookie[] cookies = request.getCookies();
  22.         if (cookies != null && cookies.length > 0) {
  23.             for (Cookie cookie : cookies) {
  24.                 //user-key
  25.                 String name = cookie.getName();
  26.                 if (name.equals(TEMP_USER_COOKIE_NAME)) {
  27.                     userInfoTo.setUserKey(cookie.getValue());
  28.                     //标记为已是临时用户
  29.                     userInfoTo.setTempUser(true);
  30.                 }
  31.             }
  32.         }
  33.         //如果没有临时用户一定分配一个临时用户
  34.         if (StringUtils.isEmpty(userInfoTo.getUserKey())) {
  35.             String uuid = UUID.randomUUID().toString();
  36.             userInfoTo.setUserKey(uuid);
  37.         }
  38.         //目标方法执行之前
  39.         toThreadLocal.set(userInfoTo);
  40.         return true;
  41.     }
  42.     /**
  43.      * 业务执行之后,分配临时用户来浏览器保存
  44.      * @param request
  45.      * @param response
  46.      * @param handler
  47.      * @param modelAndView
  48.      * @throws Exception
  49.      */
  50.     @Override
  51.     public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
  52.         //获取当前用户的值
  53.         UserInfoTo userInfoTo = toThreadLocal.get();
  54.         //如果没有临时用户一定保存一个临时用户
  55.         if (!userInfoTo.getTempUser()) {
  56.             //创建一个cookie
  57.             Cookie cookie = new Cookie(TEMP_USER_COOKIE_NAME, userInfoTo.getUserKey());
  58.             //扩大作用域
  59.             cookie.setDomain("gulimall.com");
  60.             //设置过期时间
  61.             cookie.setMaxAge(TEMP_USER_COOKIE_TIMEOUT);
  62.             response.addCookie(cookie);
  63.         }
  64.     }
  65.     @Override
  66.     public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
  67.     }
  68. }
复制代码
面试问题:你是如何在项目中使用ThreadLocal的?
ThreadLocal来共享同一个线程中的数据。每一个请求,tomcat会开辟一个线程来处理请求,从拦截器的执行,到调用controller、service、dao,一直到请求结束返回,都是在同一个线程中实现的。
在购物车项目中,我们需要一个拦截器来进行用户身份的鉴别,拦截器中创建一个ThreadLocal来放用户登录信息,然后在执行其他操作时,需要登录信息时,只需要get到即可。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

伤心客

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表