ToB企服应用市场:ToB评测及商务社交产业平台
标题:
Java打怪之路----谷粒商场认证服务
[打印本页]
作者:
伤心客
时间:
2022-6-25 16:17
标题:
Java打怪之路----谷粒商场认证服务
一、登录注册功能
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解决子域共享问题
引入依赖
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
复制代码
配置文件中配置
spring:
session:
store-type: redis
复制代码
主启动类中添加注解:@EnableRedisHttpSession
至此,可以保证session存入redis中。
然而,默认发的令牌。sessionid=abc的作用域是在当前域,需要解决子域session共享问题。
扩大子域范围
@Configuration
public class AchangmallSessionConfig {
@Bean
public CookieSerializer cookieSerializer() {
DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
//放大作用域
cookieSerializer.setDomainName("gulimall.com");
cookieSerializer.setCookieName("ACHANGSESSION");
return cookieSerializer;
}
@Bean
public RedisSerializer<Object> springSessionDefaultRedisSerializer() {//使用json存储redis,而不是默认的序列化存储
return new GenericJackson2JsonRedisSerializer();
}
} Y
复制代码
原理
三、购物车
3.1ThreadLocal用户身份鉴别
用户身份鉴别流程:
获取购物车之前首先要判断是否登录,需要整合springsession来共享数据
第一次使用购物车功能,会给一个临时用户身份
浏览器有一个cookie:use-key:标识用户身份,一个月后过期
浏览器以后保存,每次访问都会带上这个cookie
登录:session中有相关信息
未登录:按照cookie中的user-key
第一次使用:没有临时用户就要创建一个临时用户。
这里采用
拦截器
来实现
具体实现:
拦截器配置
拦截器的注册:
@Configuration
public class GulimallWebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new CartInterceptor())//注册拦截器
.addPathPatterns("/**");
}
}
复制代码
购物车的拦截器实现spring中的HandlerInterceptor接口
public class CartInterceptor implements HandlerInterceptor {
public static ThreadLocal<UserInfoTo> toThreadLocal = new ThreadLocal<>();
/***
* 目标方法执行之前
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
UserInfoTo userInfoTo = new UserInfoTo();
HttpSession session = request.getSession();
//获得当前登录用户的信息
MemberResponseVo memberResponseVo = (MemberResponseVo) session.getAttribute(LOGIN_USER);
if (memberResponseVo != null) {
//用户登录了
userInfoTo.setUserId(memberResponseVo.getId());
}
Cookie[] cookies = request.getCookies();
if (cookies != null && cookies.length > 0) {
for (Cookie cookie : cookies) {
//user-key
String name = cookie.getName();
if (name.equals(TEMP_USER_COOKIE_NAME)) {
userInfoTo.setUserKey(cookie.getValue());
//标记为已是临时用户
userInfoTo.setTempUser(true);
}
}
}
//如果没有临时用户一定分配一个临时用户
if (StringUtils.isEmpty(userInfoTo.getUserKey())) {
String uuid = UUID.randomUUID().toString();
userInfoTo.setUserKey(uuid);
}
//目标方法执行之前
toThreadLocal.set(userInfoTo);
return true;
}
/**
* 业务执行之后,分配临时用户来浏览器保存
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
//获取当前用户的值
UserInfoTo userInfoTo = toThreadLocal.get();
//如果没有临时用户一定保存一个临时用户
if (!userInfoTo.getTempUser()) {
//创建一个cookie
Cookie cookie = new Cookie(TEMP_USER_COOKIE_NAME, userInfoTo.getUserKey());
//扩大作用域
cookie.setDomain("gulimall.com");
//设置过期时间
cookie.setMaxAge(TEMP_USER_COOKIE_TIMEOUT);
response.addCookie(cookie);
}
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
复制代码
面试问题:
你是如何在项目中使用ThreadLocal的?
ThreadLocal来共享同一个线程中的数据。每一个请求,tomcat会开辟一个线程来处理请求,从拦截器的执行,到调用controller、service、dao,一直到请求结束返回,都是在同一个线程中实现的。
在购物车项目中,我们需要一个拦截器来进行用户身份的鉴别,拦截器中创建一个ThreadLocal来放用户登录信息,然后在执行其他操作时,需要登录信息时,只需要get到即可。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/)
Powered by Discuz! X3.4