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

项目网站建设应入哪个科目seo的优化原理

项目网站建设应入哪个科目,seo的优化原理,网站建设实战,有哪些免费做外贸的网站Redis实战 — 黑马点评(一) 登录篇 来自黑马的redis课程的笔记 【黑马程序员Redis入门到实战教程,深度透析redis底层原理redis分布式锁企业解决方案黑马点评实战项目】 目录Redis实战 — 黑马点评(一) 登录篇1. 项目…

Redis实战 — 黑马点评(一) 登录篇

来自黑马的redis课程的笔记

【黑马程序员Redis入门到实战教程,深度透析redis底层原理+redis分布式锁+企业解决方案+黑马点评实战项目】

目录

  • Redis实战 — 黑马点评(一) 登录篇
    • 1. 项目介绍
    • 2. 短信登录
      • 2.1 流程:
      • 2.2 一些小的收获
      • 2.3 系统安全(重点)
      • 2.4 实现流程和关键代码
        • 2.4.1 发送验证码
        • 2.4.2 短信验证码登录/注册
        • 2.4.3 校验登录状态

1. 项目介绍

在这里插入图片描述

在这里插入图片描述

2. 短信登录

2.1 流程:

在这里插入图片描述

2.2 一些小的收获

  • 使用hutool中的RandomUtil.randomNumbers(6)RandomUtil.randomString(10)随机生成验证码和随机字符串(用于默认用户名)

  • 代码中不要出现“魔法值”,要统一定义常量

  • mp中lambdaQuery的使用(相信之后不用再new QueryWrapper了)

    User user = lambdaQuery().eq(User::getPhone, phone).one();
    
  • 使用UUID.randomUUID().toString(true)来生成不带‘-’的uuid

  • // 使用hutool工具中的对象转map,并自定义操作。
    Map<String, Object> userMap = BeanUtil.beanToMap(userDTO, new HashMap<>(),CopyOptions.create().ignoreNullValue().setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString()));
    
  • 封装好的常用的正则表达式和正则工具类

    public abstract class RegexPatterns {/*** 手机号正则* 使用过程中发现有些手机号不支持如191这些新手机号,自行修改即可,例如要支持191,只需将9[89]改为9[189]* 括号里面的就是第2,3位手机号*/public static final String PHONE_REGEX = "^1([38][0-9]|4[579]|5[0-3,5-9]|6[6]|7[0135678]|9[89])\\d{8}$";/*** 邮箱正则*/public static final String EMAIL_REGEX = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$";/*** 密码正则。4~32位的字母、数字、下划线*/public static final String PASSWORD_REGEX = "^\\w{4,32}$";/*** 验证码正则, 6位数字或字母*/public static final String VERIFY_CODE_REGEX = "^[a-zA-Z\\d]{6}$";}
    
    public class RegexUtils {/*** 是否是无效手机格式* @param phone 要校验的手机号* @return true:不符合,false:符合*/public static boolean isPhoneInvalid(String phone){return mismatch(phone, RegexPatterns.PHONE_REGEX);}/*** 是否是无效邮箱格式* @param email 要校验的邮箱* @return true:不符合,false:符合*/public static boolean isEmailInvalid(String email){return mismatch(email, RegexPatterns.EMAIL_REGEX);}/*** 是否是无效验证码格式* @param code 要校验的验证码* @return true:不符合,false:符合*/public static boolean isCodeInvalid(String code){return mismatch(code, RegexPatterns.VERIFY_CODE_REGEX);}// 校验是否不符合正则格式private static boolean mismatch(String str, String regex){if (StrUtil.isBlank(str)) {return true;}return !str.matches(regex);}
    }
    

2.3 系统安全(重点)

用户登录,管理的三种常见方案:

  1. 传统的cookie + session

    流程:

    1、用户向服务器发送用户名和密码。

    2、服务器验证通过后,在当前对话(session)里面保存相关数据,比如用户角色、登录时间等等。

    3、服务器向用户返回一个 session_id,写入用户的 Cookie。

    4、用户随后的每一次请求,都会通过 Cookie,将 session_id 传回服务器。

    5、服务器收到 session_id,找到前期保存的数据,由此得知用户的身份。

    优点:

    • 数据存放在服务端,客户端只拿到令牌,服务端对用户状态掌控力强。

    缺点:

    • 浏览器支持cookie,移动端不行。
    • session是存放在服务端程序内存中的,分布式架构下session共享是个问题,不易水平扩展。
  2. JWT

    流程:

    1、用户向服务器发送用户名和密码。

    2、服务器验证通过后,颁发一个jwt字符串,该字符串中可以包含一些不敏感的用户信息

    3、客户端存储jwt。

    4、用户随后的每一次请求,都会带上jwt,服务端验证jwt判断用户是否合法。

    优点:

    • 去中心化,便于分布式系统使用。
    • 基本信息可以直接放在token中。 username,nickname,role等。

    缺点:

    • 一旦颁发jwt,该jwt在有效期内都有效,服务端不能主动让其失效。
  3. token + redis

    该方案就是cookie + session的一个升级版,其思想是一样的。

    也就是让redis代替session,让token代替sessionid。

    流程:

    1、用户向服务器发送用户名和密码。

    2、服务器验证通过后,在redis里面保存相关数据,比如用户角色、登录时间等等。

    3、服务器向用户返回一个 token。

    4、用户随后的每一次请求,都会带上该token。

    5、服务器收到 token,在redis中找到前期保存的数据,由此得知用户的身份。

    优点:

    • 数据存放在服务端,客户端只拿到令牌,服务端对用户状态掌控力强。
    • 用redis代替session后,不再担心分布式架构session共享的问题,性能好。

    缺点:

    • 依赖redis,redis操作增加系统复杂度。

redis课程当然采用的是第三种方案。

jwt的致命缺点就是无法主动踢出用户,个人感觉用户管理最佳方案就是token + redis的方式,遇到瓶颈只需要横向扩展redis即可。

2.4 实现流程和关键代码

2.4.1 发送验证码

要考虑的问题:

  • 如何生成验证码?

  • 验证码有效期如何实现?

  • 如何将手机号和验证码绑定?

  • 如何发送短信?

解决:

  • 使用RandomUtil.randomNumbers(6);生成随机六位验证码。
  • 使用redis的特性,设置该数据的ttl。
  • 将手机号作为key,验证码作为value。
  • 购买短信服务。
@Autowired
StringRedisTemplate stringRedisTemplate;@Override
public Result sendCode(String phone, HttpSession session) {// 1. 校验手机号if (RegexUtils.isPhoneInvalid(phone)) {// 2. 若不符合,返回错误信息return Result.fail("手机号格式错误!");}// 3. 符合,生成验证码String code = RandomUtil.randomNumbers(6);// 4. 保存验证码和手机号到redis, 设置过期时间, 此处LOGIN_CODE_TTL为避免产生魔法值而设置的常量 2LstringRedisTemplate.opsForValue().set(LOGIN_CODE_KEY + phone, code, LOGIN_CODE_TTL, TimeUnit.MINUTES);// 5. 发送验证码(此处没钱购买服务,一般可以去各大云购买短信服务调用相应的api)log.debug("发送验证码成功,验证码:{}", code);return Result.ok();
}

2.4.2 短信验证码登录/注册

跟着流程走即可,前端需要保存此处返回的token:

@Override
public Result login(LoginFormDTO loginForm, HttpSession session) {// 1. 校验手机号String phone = loginForm.getPhone();if (RegexUtils.isPhoneInvalid(phone)) {// 2. 若不符合,返回错误信息return Result.fail("手机号格式错误!");}// 2. 校验验证码String cacheCode = stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEY + phone);String code = loginForm.getCode();if (StrUtil.isBlank(code) || !code.equals(cacheCode)) {// 3. 不一致 报错return Result.fail("验证码错误");}// 4. 一致 根据手机号查询用户User user = lambdaQuery().eq(User::getPhone, phone).one();// 5. 判断用户是否存在if (user == null) {// 6. 不存在 创建用户user = createUserWithPhone(phone);}// 7. 存在 保存到session/redis// 7.1 随机生成token,作为登录令牌String token = UUID.randomUUID().toString(true);// 7.2 将user转为hashmap存储UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);Map<String, Object> userMap = BeanUtil.beanToMap(userDTO, new HashMap<>(),CopyOptions.create().ignoreNullValue().setFieldValueEditor((name, value) -> value.toString()));// 7.3 存储stringRedisTemplate.opsForHash().putAll(LOGIN_USER_KEY + token, userMap);stringRedisTemplate.expire(LOGIN_USER_KEY + token, LOGIN_USER_TTL, TimeUnit.MINUTES);// 8. 返回tokenreturn Result.ok(token);
}// 创建用户
private User createUserWithPhone(String phone) {// 1. 创建用户User user = new User();user.setPhone(phone);user.setNickName(USER_NICK_NAME_PREFIX + RandomUtil.randomString(10));// 2. 保存用户save(user);return user;
}

2.4.3 校验登录状态

主要是使用拦截器实现,知识点:

  • 拦截无权限请求

  • token自动续签

  • 使用ThreadLocal

思路:

一个拦截器用于token续签,一个拦截器用于权限验证。

在这里插入图片描述

token续签:

小tips:由于注册拦截器需要手动new,所以我们不使用自动装配的方式来注入StringRedisTemplate,而是使用构造方法在注册拦截器的时候注入。

public class RefreshTokenInterceptor implements HandlerInterceptor {private StringRedisTemplate stringRedisTemplate;public RefreshTokenInterceptor(StringRedisTemplate stringRedisTemplate) {this.stringRedisTemplate = stringRedisTemplate;}@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 1. 获取请求头中tokenString token = request.getHeader("authorization");if (StrUtil.isBlank(token)) {return true;}// 2. 获取redis中的用户String key = LOGIN_USER_KEY + token;Map<Object, Object> userMap = stringRedisTemplate.opsForHash().entries(key);// 3. 判断用户是否存在if (userMap.isEmpty()) {return true;}
//        UserDTO user = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);UserDTO user = BeanUtil.toBean(userMap, UserDTO.class);// 5. 存在 保存用户信息到ThreadLocalUserHolder.saveUser(user);// 6. 刷新token有效期stringRedisTemplate.expire(key, RedisConstants.LOGIN_USER_TTL, TimeUnit.MINUTES);// 7. 放行return true;}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {UserHolder.removeUser();}
}

权限验证:

public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {if (UserHolder.getUser() == null) {response.setStatus(HttpStatus.HTTP_UNAUTHORIZED);return false;}return true;}
}

拦截器注册:

小tips:

  • 在这里自动装配StringRedisTemplate,通过构造函数注入RefreshTokenInterceptor,使代码更优雅。

  • 不是所有请求都需要权限验证,所以根据需求设置白名单。

  • 使用order来设置拦截器的优先级,order越小,优先级越高,order相同,优先级按注册顺序降低。

@Configuration
public class MvcConfig implements WebMvcConfigurer {@AutowiredStringRedisTemplate stringRedisTemplate;@Overridepublic void addInterceptors(InterceptorRegistry registry) {List<String> excludePath = new ArrayList<>();excludePath.add("/user/code");excludePath.add("/user/login");excludePath.add("/blog/hot");excludePath.add("/shop/**");excludePath.add("/shop-type/**");excludePath.add("/upload/**");excludePath.add("/voucher/**");registry.addInterceptor(new LoginInterceptor()).excludePathPatterns(excludePath).order(1);registry.addInterceptor(new RefreshTokenInterceptor(stringRedisTemplate)).addPathPatterns("/**").order(0);}
}
http://www.hkea.cn/news/770847/

相关文章:

  • 鲜花购物网站源码企业网站营销的优缺点
  • 表白网站制作在线日照网站优化公司
  • 企业网站建设策划书 前言徐州关键词优化排名
  • 一级a做爰片视频网站全国新闻媒体发稿平台
  • 唐山网站建设哪家专业高德北斗导航
  • wordpress 地址 .html企业网站seo贵不贵
  • 提供网站制作公司哪家好网络软文范文
  • 做原型网站枣庄网络推广seo
  • 品牌网站开发设计外贸网站平台
  • 网站做留言板网站推广在线
  • 长春服务好的网络营销seo网站推广的主要目的
  • 搜索引擎优化和关键词竞价广告的区别宿州百度seo排名软件
  • 一搜同志网站建设电话青岛网站seo优化
  • 官方做任务网站网络营销公司注册找哪家
  • django做视频网站网络营销推广专家
  • 国外手做网站搜索引擎推广的关键词
  • 网站建设商标注册多少类目域名注册免费
  • 哪里有网站设计公司长沙网络公司最新消息
  • 试描述一下网站建设的基本流程百度怎么发布短视频
  • 我现在有域名怎么做网站搜索关键词热度
  • 海外如何 淘宝网站建设快速seo整站优化排行
  • 代还信用卡网站建设赣州seo顾问
  • 响应式网站建设推广开网店
  • 成都专业网站推广公司优化大师优化项目有
  • 怎么用wordpress搭建网站百度关键词排名点
  • 外挂网站模板域名搜索引擎入口
  • 手机网站开发 pdfseo搜索引擎优化工作内容
  • 上海中小网站建设洛阳seo博客
  • 南宁网站建设公司哪家专业搜索引擎优化包括
  • 新疆住房与建设厅网站新产品推广方式有哪些