黑马点评技术汇总(一)验证码登录
一、session实现验证码登录总思路前端提交手机号发起code请求服务端校验手机号是否符合格式成功后生成验证码存入session并发送给用户。用户提交手机号和验证码验证手机是否符合格式这里有个bug验证码是否和session中的验证码一致成功后查询数据库是否有该手机号如果由就保存用户信息到session中因为拦截器要校验登陆信息如果没有就就进行注册后保存。拦截器从session中获取用户信息判断用户是否存在如果存在就存放在ThreadLocal方便以后其他类需要使用当前登录用户信息。UserControllerSlf4j RestController RequestMapping(/user) public class UserController { Resource private IUserService userService; Resource private IUserInfoService userInfoService; /** * 发送手机验证码 */ PostMapping(/code) public Result sendCode(RequestParam(phone) String phone, HttpSession session) { // 发送短信验证码并保存验证码 return userService.sendCode(phone,session); } /** * 登录功能 * param loginForm 登录参数包含手机号、验证码或者手机号、密码 */ PostMapping(/login) public Result login(RequestBody LoginFormDTO loginForm, HttpSession session){ // 实现登录功能 return userService.login(loginForm,session); } /** * 登出功能 * return 无 */ PostMapping(/logout) public Result logout(){ // TODO 实现登出功能 return Result.fail(功能未完成); } GetMapping(/me) public Result me(){ //获取当前登录的用户并返回 UserDTO user UserHolder.getUser(); return Result.ok(user); } GetMapping(/info/{id}) public Result info(PathVariable(id) Long userId){ // 查询详情 UserInfo info userInfoService.getById(userId); if (info null) { // 没有详情应该是第一次查看详情 return Result.ok(); } info.setCreateTime(null); info.setUpdateTime(null); // 返回 return Result.ok(info); } }UserServiceSlf4j Service public class UserServiceImpl extends ServiceImplUserMapper, User implements IUserService { /** * 发送短信验证码 * param phone * param session * return */ Override public Result sendCode(String phone, HttpSession session) { //校验手机号 if(RegexUtils.isPhoneInvalid(phone)){ //不符合返回错误 return Result.fail(手机号格式错误); } //符合生成验证码 String code RandomUtil.randomNumbers(6); //保存验证码到session session.setAttribute(code,code); //发送验证码 log.debug(发送短信验证码成功,验证码:{},code); //返回ok return Result.ok(); } /** * 登录 * param loginForm * param session * return */ Override public Result login(LoginFormDTO loginForm, HttpSession session) { //校验手机号 String phone loginForm.getPhone(); if(RegexUtils.isPhoneInvalid(phone)){ return Result.fail(手机号格式错误); } //校验验证码 String code loginForm.getCode(); Object cacheCode session.getAttribute(code); if(cacheCodenull||!cacheCode.toString().equals(code)){ //不一致报错 return Result.fail(验证码错误); } //一致根据手机号查询用户 User user query().eq(phone, phone).one(); //判断用户是否存在 if(usernull){ //不存在创建新用户并保存 user createUserWithPhone(phone); } //保存用户信息到session UserDTO userDTO BeanUtil.copyProperties(user, UserDTO.class); session.setAttribute(user,userDTO); return Result.ok(); } private User createUserWithPhone(String phone) { User user new User(); user.setPhone(phone); user.setNickName(USER_NICK_NAME_PREFIX RandomUtil.randomString(10)); //保存用户 save(user); return user; } }UserHolderpublic class UserHolder { private static final ThreadLocalUserDTO tl new ThreadLocal(); public static void saveUser(UserDTO user){ tl.set(user); } public static UserDTO getUser(){ return tl.get(); } public static void removeUser(){ tl.remove(); } }二、redis实现登录由于在多台tomcat服务器不能实现session共享我们就统一放到redis中redis集群是共享数据的每个redis服务器存放不同数据。Slf4j Service public class UserServiceImpl extends ServiceImplUserMapper, User implements IUserService { Resource private StringRedisTemplate stringRedisTemplate; /** * 发送短信验证码 * param phone * param session * return */ Override public Result sendCode(String phone, HttpSession session) { //校验手机号 if(RegexUtils.isPhoneInvalid(phone)){ //不符合返回错误 return Result.fail(手机号格式错误); } //符合生成验证码 String code RandomUtil.randomNumbers(6); //保存验证码到redis stringRedisTemplate.opsForValue().set(LOGIN_CODE_KEYphone,code,LOGIN_USER_TTL, TimeUnit.MINUTES); //发送验证码 log.debug(发送短信验证码成功,验证码:{},code); //返回ok return Result.ok(); } /** * 登录 * param loginForm * param session * return */ Override public Result login(LoginFormDTO loginForm, HttpSession session) { //校验手机号 String phone loginForm.getPhone(); if(RegexUtils.isPhoneInvalid(phone)){ return Result.fail(手机号格式错误); } //校验验证码 String code loginForm.getCode(); //从redis获取验证码 String cacheCode stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEYphone); if(cacheCodenull||!cacheCode.equals(code)){ //不一致报错 return Result.fail(验证码错误); } //一致根据手机号查询用户 User user query().eq(phone, phone).one(); //判断用户是否存在 if(usernull){ //不存在创建新用户并保存 user createUserWithPhone(phone); } //保存用户信息到redis //随机生成token作为登录令牌 String token UUID.randomUUID().toString(); //将User对象转为Hash存储 UserDTO userDTO BeanUtil.copyProperties(user, UserDTO.class); MapString, Object map BeanUtil.beanToMap(userDTO,new HashMap(), CopyOptions.create() .setIgnoreNullValue(true) .setFieldValueEditor((fieldName, filedValue) -filedValue.toString())); //存储 String tokenKey LOGIN_USER_KEY token; stringRedisTemplate.opsForHash().putAll(tokenKey,map); //设置过期时间 stringRedisTemplate.expire(tokenKey,LOGIN_USER_TTL,TimeUnit.MINUTES); //返回token return Result.ok(token); } private User createUserWithPhone(String phone) { User user new User(); user.setPhone(phone); user.setNickName(USER_NICK_NAME_PREFIX RandomUtil.randomString(10)); //保存用户 save(user); return user; } }package com.hmdp.utils; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.util.StrUtil; import com.hmdp.dto.UserDTO; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.util.Map; import java.util.concurrent.TimeUnit; import static net.sf.jsqlparser.util.validation.metadata.NamedObject.user; public class LoginInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 判断是否需要拦截 if(UserHolder.getUser() null){ response.setStatus(401); return false; } return true; } Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { UserHolder.removeUser(); } }package com.hmdp.utils; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.util.StrUtil; import com.hmdp.dto.UserDTO; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.Map; import java.util.concurrent.TimeUnit; public class RefreshTokenInterceptor implements HandlerInterceptor { private StringRedisTemplate stringRedisTemplate; public RefreshTokenInterceptor(StringRedisTemplate stringRedisTemplate) { this.stringRedisTemplate stringRedisTemplate; } Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //请求头中的token String token request.getHeader(authorization); if(StrUtil.isBlank(token)){ return true; } //基于token获取redis中的用户 String key RedisConstants.LOGIN_USER_KEY token; MapObject, Object userMap stringRedisTemplate.opsForHash() .entries(key); //判断用户是否存在 if(userMap.isEmpty()){ return true; } //将查询道德Hash数据转为UserDTO对象 UserDTO userDTO BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false); //存在保存用户信息到ThreadLocal UserHolder.saveUser(userDTO); //刷新token有效期 stringRedisTemplate.expire(key, RedisConstants.LOGIN_USER_TTL, TimeUnit.MINUTES); return true; } Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { UserHolder.removeUser(); } }package com.hmdp.config; import com.hmdp.utils.LoginInterceptor; import com.hmdp.utils.RefreshTokenInterceptor; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import javax.annotation.Resource; Configuration public class MvcConfig implements WebMvcConfigurer { Resource private StringRedisTemplate stringRedisTemplate; Override public void addInterceptors(InterceptorRegistry registry) { //token刷新的拦截器 registry.addInterceptor(new RefreshTokenInterceptor(stringRedisTemplate)).addPathPatterns(/**).order(0); //登录拦截器 registry.addInterceptor(new LoginInterceptor()) .excludePathPatterns( /user/code, /user/login, /blog/hot, /shop/**, /shop-type/**, /upload/**, /voucher/** ).order(1); } }
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2452369.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!