mmall商城用户模块开发总结
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商城用户模块开发总结的更多相关文章
- 小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_5-8.用户模块开发之保存微信用户信息
笔记 8.用户模块开发之保存微信用户信息 简介:开发User数据访问层,保存微信用户信息 问题: 微信回调 用户昵称乱码 解决: ...
- python-django框架-电商项目-用户模块开发_20191117
实现注册的基本逻辑: 1,注册页面 注意:注册页面需要静态文件的支持,另外注册页面是基础基类的, 1,url,路由系统, 2,views,视图系统,还是使用类视图,里面有很多的函数, 2,views. ...
- mmall商城购物车模块总结
购物车模块的设计思想 购物车的实现方式有很多,但是最常见的就三种:Cookie,Session,数据库.三种方法各有优劣,适合的场景各不相同.Cookie方法:通过把购物车中的商品数据写入Cookie ...
- mmall商城分类模块总结
后台分类model的开发具体功能有:添加分类名称,修改分类名称,查询所有子分类,查询父分类以及它下面的子分类(递归) 需要注意的是,在后台管理进行操作的时候,都需要验证当前用户是否是管理员的角色,不管 ...
- 【JAVAWEB学习笔记】网上商城实战:环境搭建和完成用户模块
网上商城实战 今日任务 完成用户模块的功能 1.1 网上商城的实战: 1.1.1 演示网上商城的功能: 1.1.2 制作目的: 灵活运用所学知识完成商城实战. 1.1.3 ...
- 【JAVAWEB学习笔记】网上商城实战1:环境搭建和完成用户模块
今日任务 完成用户模块的功能 1.1 网上商城的实战: 1.1.1 演示网上商城的功能: 1.1.2 制作目的: 灵活运用所学知识完成商城实战. 1.1.3 数据库分析和设 ...
- 【青橙商城-管理后台开发】3. web模块搭建
[青橙商城-管理后台开发]3. web模块搭建 1.创建qingcheng_web_manager模块 pom.xml <?xml version="1.0" encodin ...
- JavaWeb网上图书商城完整项目--21.用户模块各层相关类的创建
1.现在要为user用户模块创建类 用户模块功能包括:注册.激活.登录.退出.修改密码. User类对照着t_user表来写即可.我们要保证User类的属性名称与t_user表的列名称完全相同. 我们 ...
- Asp.net Mvc模块化开发之“开启模块开发、调试的简单愉快之旅”
整个世界林林种种,把所有的事情都划分为对立的两个面. 每个人都渴望的财富划分为富有和贫穷,身高被划分为高和矮,身材被划分为胖和瘦,等等. 我们总是感叹,有钱人的生活我不懂;有钱人又何尝能懂我们每天起早 ...
随机推荐
- CF1400F - x-prime Substrings
1400F - x-prime Substrings 首先发现 \(x\) 很小,所以发现对应的 x-prime 字符串数也很少,最多的情况是 \(x = 19\),有 2399 个,先爆搜出来. 现 ...
- Codeforces Edu Round 61 A-C + F
A. Regular Bracket Sequence 显然,"\(()\)"不影响结果它是自我匹配的,可以把所有的\(((\)和\())\)都放在左边/右边,这样只要检查它们的数 ...
- elastic-job分布式调度与zookeeper的简单应用
一.对分布式调度的理解 调度->定时任务,分布式调度->在分布式集群环境下定时任务这件事 Elastic-job(当当⽹开源的分布式调度框架) 1 定时任务的场景 定时任务形式:每隔⼀定时 ...
- 通过git-bash 批量管理VMware虚拟机
#先将vmrun .exe 加入环境变量 # 我这里是: ;C:\Program Files (x86)\VMware\VMware VIX; #cd E:/期中架构/#sh new\ 3.bash ...
- 优化Windows电脑常见方法,提高速度,释放硬盘C盘
开始,我们首先让电脑变得易于使用一,提高开机速度常见的使电脑变卡的原因是:一台电脑同时安装了多个杀毒软件.一台电脑安装多个杀毒软件不仅占用你电脑大量内存.有时甚至会产生冲突,这会导致电脑运行非常缓慢, ...
- CTF-源码泄露-PHP备份文件的两种格式
参考大佬文章: https://www.cnblogs.com/yunqian2017/p/11515443.html https://blog.csdn.net/xy_sunny/article/d ...
- (第一篇)记一次python分布式web开发(利用docker)
作者:落阳 日期:2020-12-23 在一次项目开发中,决定使用docker+nginx+flask+mysql的技术栈来开发,用此系列文章记录开发的过程. 系列文章,当前为第一篇,记录一次pyth ...
- Windows 上安装 PostgreSQL
PostgreSQL官网–>Download–>Windows 64位,如图所示: (1)官网: https://www.postgresql.org/ (2)Download: http ...
- 使用CentOS8搭建私有NAS存储的一些建议
对于超过2TB的硬盘来说只能考虑GPT分区表,因此还是建议使用EFI来安装系统. 对于超过2TB的硬盘来说应该选择LVM,然后磁盘末尾预留出至少100G的空间用于将来方便维护安装个Windows系统之 ...
- springMVC框架配置定时器
在springmvc.xml添加如下内容在xmlns中添加 xmlns:task="http://www.springframework.org/schema/task"1在xsi ...