1、需要实现的功能介绍

注册 登录 用户名校验
忘记密码 提交问题答案 重置密码
获取用户信息 更新用户信息 退出登录

目标

  • 避免横向越权,纵向越权的安全漏洞
  • MD5明文加密级增加的salt值
  • Guava缓存的使用
  • 高复用服务响应对象的设计思想级抽象封装
  • session的使用

横向越权:攻击者尝试访问与他人拥有相同权限的用户。
纵向越权:低级别攻击者尝试访问高级别用户的资源

当用户在未登录的状态下修改密码时,用户回答了忘记密码的答案然后生成一个具有时间限制的token,这里用UUID表示,之后再跳转到重置密码界面输入新的密码提交,这里设置token的作用就是避免横向越权,如果一个网络攻击者直接进入重置密码页面,这里会进行检测他提交时是不是有正确的token,并且我们可以设置token的生效时间,这样就提高了安全性,当然密码的存储是经过MD5加密的,所以数据库看到的是加密后的密码。如果用户在登陆成功后,进行修改的话,我们不需要这么做。

用户重置密码阶段

这个阶段是在用户正确回答自己设置的问题后,拿到了服务器生成的token后进行密码重置,这时该进行怎样的处理呢?
首先前台表单中我们可以获取到用户名,提交表单携带的token,和新的密码。其次,我们先要验证的是传过来的token,如果他为空或者是个空串,或者包含空格,那就不合法,返回参数错误信息;然后,校验用户名,这时候为什么要再次校验username呢?因为在本地保存token时,我把username当做key,生成的token当做了value,所以在后面获取本地储存的token时,要保证username的正确,才能获取本地的token,校验完username后。下一步,我们开始从本地获取token,获取后需要校验一下本地的是不是为空或者是空串,这时才把两个token进行比较,当前台传过来的token与本地服务器端的token一样时,我们才开始更新密码,记得在更新前对新的密码进行加密,HDMC或者MD5方式,加密后才根据username更新密码字段,记得要带上更新时间,也就是一起把update_time也更新了。如果两个token不一样,那就设置错误的状态吗,提示token错误,请重新回答密保问题后再次进行更改。

核心代码如下


public ServerResponse<String> forgetResetPassword(String username, String passwordNew, String forgetToken) {
if (StringUtils.isBlank(forgetToken)) {
return ServerResponse.createByErrorMessage("参数错误,token需要传递");
}
//需要校验用户名,因为tokenCache的key包含username
ServerResponse<String> checkValid = this.checkValid(username, Const.USERNAME);
if (checkValid.isSuccess()) {
//用户名不存在
return ServerResponse.createByErrorMessage("用户不存在");
}
String token = TokenCache.getKey(TokenCache.TOKEN_PREFIX + username);
if (StringUtils.isBlank(token)) {
return ServerResponse.createByErrorMessage("token无效或过期");
}
if (StringUtils.equals(forgetToken,token)){
//这时开始更新password,先加密在保存
String md5Password = MD5Util.MD5EncodeUtf8(passwordNew);
int rowCount = userMapper.updatePasswordByUsername(username, md5Password);
if (rowCount>0){
return ServerResponse.createBySuccessMessage("修改密码成功");
}
}else{
//如果两个token不一样,那就重新获取新的token
return ServerResponse.createByErrorMessage("token错误,请重新回答问题后获取重置密码的token");
}
return ServerResponse.createByErrorMessage("修改密码失败");
}

当用户回答完忘记密码的问题后,提交的用户名,问题,答案要在数据库中进行查询如果查到的记录数为1,代表问题与答案相匹配,然后生成token,这里也就是一个UUID,把这个token放在本地的token缓存中,以键值对的形式存储,token_username代表key,生成的UUID代表value,最后返回前端的数据是生成的token。代码如下

public ServerResponse<String> checkAnswer(String username, String question, String answer) {

        int resultCount = userMapper.checkAnswer(username, question, answer);
if (resultCount > 0) {
//问题答案匹配成功
String forgetToken = UUID.randomUUID().toString();
TokenCache.setKey(TokenCache.TOKEN_PREFIX + username, forgetToken);
return ServerResponse.createBySuccessData(forgetToken);
}
return ServerResponse.createByErrorMessage("问题的答案错误");
}

TokenCache类:

 private static Logger logger = LoggerFactory.getLogger(TokenCache.class);
public static final String TOKEN_PREFIX = "token_"; //LRU算法
private static LoadingCache<String, String> localCache =
CacheBuilder.newBuilder()
.initialCapacity(1000)
.maximumSize(10000)
.expireAfterAccess(12, TimeUnit.HOURS)
.build(new CacheLoader<String, String>() {
//默认的数据加载实现,当key没有对应的值时,就调用这个方法进行加载
@Override
public String load(String s) throws Exception {
return "null";
}
}); public static void setKey(String key, String value) {
localCache.put(key, value);
} public static String getKey(String key){
String value = null;
try {
value = localCache.get(key);
if ("null".equals(value)){
return null;
}
return value;
} catch (ExecutionException e) {
logger.error("localCache get error",e);
}
return null;
}

现在纯粹的MD5加密已经不安全了,因为有专门解密的相关网站,只要将加密后的密文粘贴上去就可以看到解密的密码。所以为了保存数据传入的安全性,我们需要加上盐值,再用MD5生成密文,只要对方获取不到盐值,他解密是很难的。来看一下怎样使用加盐的方式进行加密。
例如在注册的接口中:

注册过程

首先前台提交过来了一大堆内容,例如用户名,密码,邮箱等等,这时我们防止用户名重复,首先校验用户名不能重复,然后校验邮箱也不能重复,方法和校验用户名一样,再然后就开始对用户的密码进行加密。

public ServerResponse<String> register(User user) {
//校验用户名
ServerResponse<String> checkValid = this.checkValid(user.getUsername(), Const.USERNAME);
if (!checkValid.isSuccess()) {
return checkValid;
}
//校验email
checkValid = this.checkValid(user.getEmail(), Const.EMAIL);
if (!checkValid.isSuccess()) {
return checkValid;
}
user.setRole(Const.Role.ROLE_CUSTOMER);
//MD5加密
user.setPassword(MD5Util.MD5EncodeUtf8(user.getPassword())); int i = userMapper.insert(user);
if (i == 0) {
return ServerResponse.createByErrorMessage("注册失败");
}
return ServerResponse.createBySuccessMessage("注册成功");
}

这里开始查看MD5Util类的实现;

 public static String MD5EncodeUtf8(String origin) {
origin = origin + PropertiesUtil.getProperty("password.salt", "");
return MD5Encode(origin, "utf-8");
}

这里就是加盐的过程了,如果在配置文件中没有设置盐默认就是一个空的字符串。password+salt的字符串在进行加密。

private static String MD5Encode(String origin, String charsetname) {
String resultString = null;
try {
resultString = new String(origin);
MessageDigest md = MessageDigest.getInstance("MD5");
if (charsetname == null || "".equals(charsetname)) {
resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
} else {
resultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname)));
}
} catch (Exception exception) {
}
return resultString.toUpperCase();
}

先将字符串转化为字节数组,然后整体对字节数组进行处理,对与字节数组中的每一个字节将他自身对16进行取余,整除运算,得到的两个结果,再从预先定义的private static final

数组中获取值,最终返回。

 private static String byteArrayToHexString(byte b[]) {
StringBuffer resultSb = new StringBuffer();
for (int i = 0; i < b.length; i++) {
resultSb.append(byteToHexString(b[i]));
} return resultSb.toString();
} private static String byteToHexString(byte b) {
int n = b;
if (n < 0) {
n += 256;
}
int d1 = n / 16;
int d2 = n % 16;
return hexDigits[d1] + hexDigits[d2];
}
private static final String hexDigits[] = {"0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};

mmall商城用户模块开发总结的更多相关文章

  1. 小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_5-8.用户模块开发之保存微信用户信息

    笔记 8.用户模块开发之保存微信用户信息     简介:开发User数据访问层,保存微信用户信息 问题:             微信回调 用户昵称乱码             解决:        ...

  2. python-django框架-电商项目-用户模块开发_20191117

    实现注册的基本逻辑: 1,注册页面 注意:注册页面需要静态文件的支持,另外注册页面是基础基类的, 1,url,路由系统, 2,views,视图系统,还是使用类视图,里面有很多的函数, 2,views. ...

  3. mmall商城购物车模块总结

    购物车模块的设计思想 购物车的实现方式有很多,但是最常见的就三种:Cookie,Session,数据库.三种方法各有优劣,适合的场景各不相同.Cookie方法:通过把购物车中的商品数据写入Cookie ...

  4. mmall商城分类模块总结

    后台分类model的开发具体功能有:添加分类名称,修改分类名称,查询所有子分类,查询父分类以及它下面的子分类(递归) 需要注意的是,在后台管理进行操作的时候,都需要验证当前用户是否是管理员的角色,不管 ...

  5. 【JAVAWEB学习笔记】网上商城实战:环境搭建和完成用户模块

    网上商城实战 今日任务 完成用户模块的功能 1.1      网上商城的实战: 1.1.1    演示网上商城的功能: 1.1.2    制作目的: 灵活运用所学知识完成商城实战. 1.1.3    ...

  6. 【JAVAWEB学习笔记】网上商城实战1:环境搭建和完成用户模块

    今日任务 完成用户模块的功能 1.1      网上商城的实战: 1.1.1    演示网上商城的功能: 1.1.2    制作目的: 灵活运用所学知识完成商城实战. 1.1.3    数据库分析和设 ...

  7. 【青橙商城-管理后台开发】3. web模块搭建

    [青橙商城-管理后台开发]3. web模块搭建 1.创建qingcheng_web_manager模块 pom.xml <?xml version="1.0" encodin ...

  8. JavaWeb网上图书商城完整项目--21.用户模块各层相关类的创建

    1.现在要为user用户模块创建类 用户模块功能包括:注册.激活.登录.退出.修改密码. User类对照着t_user表来写即可.我们要保证User类的属性名称与t_user表的列名称完全相同. 我们 ...

  9. Asp.net Mvc模块化开发之“开启模块开发、调试的简单愉快之旅”

    整个世界林林种种,把所有的事情都划分为对立的两个面. 每个人都渴望的财富划分为富有和贫穷,身高被划分为高和矮,身材被划分为胖和瘦,等等. 我们总是感叹,有钱人的生活我不懂;有钱人又何尝能懂我们每天起早 ...

随机推荐

  1. 【SDOI2017】天才黑客(前后缀优化建图 & 最短路)

    Description 给定一张有向图,\(n\) 个点,\(m\) 条边.第 \(i\) 条边上有一个边权 \(c_i\),以及一个字符串 \(s_i\). 其中字符串 \(s_1, s_2, \c ...

  2. SpringBoot 拦截器和自定义注解判断请求是否合法

    应用场景举例: 当不同身份的用户请求一个接口时,用来校验用户某些身份,这样可以对单个字段数据进行精确权限控制,具体看代码注释 自定义注解 /** * 对比请求的用户身份是否符合 * @author l ...

  3. 1.pipeline原理

    redis基本语法:https://www.cnblogs.com/xiaonq/p/7919111.html redis四篇:https://www.cnblogs.com/xiaonq/categ ...

  4. vue第二十单元(vux的配置中模块modules的用法)

    第二十单元(vux的配置中模块modules的用法) #课程目标 1.什么是module? 2.怎么用module? 3.样板代码目录结构 #知识点 #1.modules 在Vue中State使用是单 ...

  5. Golang--函数签名相同

    Golang--函数签名相同 条件 必须函数的函数名,参数和返回值(类型,个数,顺序)都相同. 验证 例子: 定义函数类型,让相同签名的函数自动实现某个接口. Negtive: package int ...

  6. C# 编译机器码过程原理之再谈反射

    一.引言 我们知道在Java中有虚拟机,代码运行时虚拟机把Java语言编译成与机器无关的字节码,然后再把字节码编译成机器指令执行,那么在.NET中程序是如何运行的呢? 其实运行原理是一样的,.NET中 ...

  7. Java面试被经常问到的常用算法

    一.冒泡排序 原理:比较两个相邻的元素,较大的放在右边 N个数字要排序完成,总共进行N-1趟排序,每i趟的排序次数为(N-i)次 最好时间复杂度为O(N) Cmax = N(N-1)/2 = O(N2 ...

  8. idea提交svn不显示新建文件

    在idea中,使用svn提交时可能会出现 预期文件没出现在提交目录里. 是因为没有把新建文件添加到版本控制里. 解决办法:右键选择文件→subversion→add to  vcs. 自动把新文件添加 ...

  9. 容器编排系统K8s之访问控制--用户认证

    前文我们聊到了k8s的statefulset控制器相关使用说明,回顾请参考:https://www.cnblogs.com/qiuhom-1874/p/14201103.html:今天我们来聊一下k8 ...

  10. jQuery EasyUI学习二

    1.   课程介绍 1.  Datagrid组件(掌握) 2.  Dialog.form组件(掌握) 3. Layout.Tabs;(掌握) Datagrid组件 2.1.  部署运行pss启动无错 ...