Spring boot 搭建个人博客系统(二)——登录注册功能
Spring boot 搭建个人博客系统(二)——登录注册功能
一直想用Spring boot 搭建一个属于自己的博客系统,刚好前段时间学习了叶神的牛客项目课受益匪浅,乘热打铁也主要是学习,好让自己熟悉这类项目开发的基本流程。系统采用Spring boot+MyBatis+MySQL的框架进行项目开发。
项目源码:Jblog
个人主页:tuzhenyu’s page
原文地址:Spring boot 搭建个人博客系统(二)——登录注册功能
0. 思路
用户登录注册功能主要实现用户的添加,验证和记住密码一段时间内的免密码登录。用户的注册是往数据库中插入用户的用户名和密码等信息,用户的验证是从数据库中取出用户的用户名和密码等信息进行比对。明文密码存储有很大的风险,采用在密码后加salt再经过MD5加密的形式存储,这样一方面避免了用户密码信息泄露的风险,同时也防止了暴力破解密码的可能。
登录成功后生成一串字符作为ticket存储在数据库和cookie中,用于下次登录的免密码登录验证。一段时间后数据库中的ticket失效,用户需要重新登录。
1. 数据模型
系统登录注册功能需要验证用户信息,需要操纵数据库的user表和login_ticket表,使用MyBatis作为系统的ORM框架用来简化数据操作。
1.1 引入MyBatis ORM框架
(1) 在pom.xml中添加MyBatis依赖jar包和MySQL连接相关的jar包,引入MyBatis相关类库和数据库连接相关类库。
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope>
</dependency>
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.1.1</version>
</dependency>
(2) 添加MyBatis配置文件,设置MyBatis相关参数
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><settings><setting name="cacheEnabled" value="true"/><setting name="defaultStatementTimeout" value="3000"/><setting name="mapUnderscoreToCamelCase" value="true"/><setting name="useGeneratedKeys" value="true"/></settings></configuration>
(3) 在系统配置文件application.properities中配置数据库URL,用户名密码等信息,同时设置MyBatis配置文件位置。
spring.datasource.url=
spring.datasource.username=
#spring.datasource.password=
spring.datasource.password=mybatis.config-location=classpath:mybatis-config.xml
1.2 添加数据库表实体类
根据user表的具体字段设置实体类的对应字段,MyBatis的mapUnderscoreToCamelCase参数设定为true,说明数据库字段的下划线分割自动对应实体类的驼峰形式。
public class User {private int id;private String name;private String password;private String salt;private String headUrl;private String role;public User(){}public User(String name){this.name = name;this.password = "";this.salt = "";this.headUrl = "";this.role = "user";}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getSalt() {return salt;}public void setSalt(String salt) {this.salt = salt;}public String getHeadUrl() {return headUrl;}public void setHeadUrl(String headUrl) {this.headUrl = headUrl;}public String getRole() {return role;}public void setRole(String role) {this.role = role;}
}
根据login_ticket表的具体字段设置实体类的对应字段
public class LoginTicket {private int id;private int userId;private Date expired;private int status;private String ticket;public int getId() {return id;}public void setId(int id) {this.id = id;}public int getUserId() {return userId;}public void setUserId(int userId) {this.userId = userId;}public Date getExpired() {return expired;}public void setExpired(Date expired) {this.expired = expired;}public int getStatus() {return status;}public void setStatus(int status) {this.status = status;}public String getTicket() {return ticket;}public void setTicket(String ticket) {this.ticket = ticket;}
}
1.3 添加数据库操作DAO类
根据MyBatis的使用特点,创建数据库操作接口UserDao.class和LoginTicket.class,用作对数据库执行具体的操作。
@Mapper
public interface UserDao {String TABLE_NAEM = " user ";String INSERT_FIELDS = " name, password, salt, head_url ,role ";String SELECT_FIELDS = " id, " + INSERT_FIELDS;@Insert({"insert into",TABLE_NAEM,"(",INSERT_FIELDS,") values (#{name},#{password},#{salt},#{headUrl},#{role})"})public void insertUser(User user);@Select({"select",SELECT_FIELDS,"from",TABLE_NAEM,"where id=#{id}"})public User seletById(int id);@Select({"select",SELECT_FIELDS,"from",TABLE_NAEM,"where name=#{name}"})public User seletByName(@Param("name") String name);@Delete({"delete from",TABLE_NAEM,"where id=#{id}"})public void deleteById(int id);
}
@Mapper
public interface LoginTicketDao {String TABLE_NAEM = " login_ticket ";String INSERT_FIELDS = " user_id, ticket, expired, status ";String SELECT_FIELDS = " id, " + INSERT_FIELDS;@Insert({"insert into",TABLE_NAEM,"(",INSERT_FIELDS,") values (#{userId},#{ticket},#{expired},#{status})"})void insertLoginTicket(LoginTicket loginTicket);@Select({"select",SELECT_FIELDS,"from",TABLE_NAEM,"where id=#{id}"})LoginTicket seletById(int id);@Select({"select",SELECT_FIELDS,"from",TABLE_NAEM,"where ticket=#{ticket}"})LoginTicket seletByTicket(String ticket);@Update({"update",TABLE_NAEM,"set status = #{status} where ticket = #{ticket}"})void updateStatus(@Param("ticket") String ticket, @Param("status") int status);@Delete({"delete from",TABLE_NAEM,"where id=#{id}"})void deleteById(int id);
}
2. 用户注册
ORM框架的作用就是将对象与关系型数据库的表进行关联性绑定,根据插入的对象解析出对应的字段插入数据库中。用户注册是在验证注册用户名密码可用的情况下生成一个User对象插入数据库中,同时为了保护用户信息安全在密码存储时,随机生成固定长度的字符串作为salt与密码组合后讲过MD5加密存储在数据库字段中。
用户密码如果直接散列后存储在数据库中,黑客可以通过获得这个密码散列值,然后通过查散列值字典(彩虹表)的方式暴力破解,得到用户的密码;通过加salt加密的方式可以一定程度上解决这一问题,因为salt值由系统随机生成,也只有系统知道。即便黑客获取了密码的散列值但在不知道salt值的前提下暴力破解散列值的几率大大降低。
加salt加密并不能完全杜绝用户密码的泄露,因为一旦密码散列值和salt值同时泄露,黑客通过salt值重建彩虹表,依旧能够获取用户密码。只是这样的计算成本会大大增加,假设每个用户一个salt, 散列值字典的字段有10万, 一次基于salt值的字典重建就要重新生成10万个字段,那么10个密码就需要生成10个散列字典,也就是100万 个字段。因此,从某种意义上来讲,增加salt的长度也就增加了散列值字典字段的数目,也可以提高安全性。还有一种提高安全性的方式,就是salt值的动态生成。通过一定算法动态生成salt值,这样可以大大降低salt值泄露的风险。
public Map<String,String> register(String username, String password){Map<String,String> map = new HashMap<>();Random random = new Random();if (StringUtils.isBlank(username)){map.put("msg","用户名不能为空");return map;}if (StringUtils.isBlank(password)){map.put("msg","密码不能为空");return map;}User u = userDao.seletByName(username);if (u!=null){map.put("msg","用户名已经被占用");return map;}User user = new User();user.setName(username);user.setSalt(UUID.randomUUID().toString().substring(0,5));user.setHeadUrl(String.format("https://images.nowcoder.com/head/%dm.png",random.nextInt(1000)));user.setPassword(JblogUtil.MD5(password+user.getSalt()));user.setRole("user");userDao.insertUser(user);String ticket = addLoginTicket(user.getId());map.put("ticket",ticket);return map;}
3. 用户登录
用户登录主要是进行用户名和密码的验证,由于用户在注册时候会生成随机的salt值进行密码存储加密,在密码验证时需要读取用户对应的salt值组合进行散列化后与数据库中用户密码进行比对,如果一致则登录成功。
用户登录时明文传输密码存在风险,黑客可以通过抓包的方式截取用户信息。一般为了降低这种Web应用登录密码传输过程中泄露的风险,可以采用https方式传输和通过公匙和私匙的非对称加密的方式。
public Map<String,String> login(String username, String password){Map<String,String> map = new HashMap<>();Random random = new Random();if (StringUtils.isBlank(username)){map.put("msg","用户名不能为空");return map;}if (StringUtils.isBlank(password)){map.put("msg","密码不能为空");return map;}User u = userDao.seletByName(username);if (u==null){map.put("msg","用户名不存在");return map;}if (!JblogUtil.MD5(password+u.getSalt()).equals(u.getPassword())){map.put("msg","密码错误");return map;}String ticket = addLoginTicket(u.getId());map.put("ticket",ticket);return map;}
4. 免密码登录
免密码登录功能主要是通过一种自动身份验证的方式实现。用户登录或注册成功后,在一定时间内(如2个小时)再次访问同一个Web程序的任一个页面时都无需再次登录,而是直接进入界面(仅限于本机)。实现这个功能关键就是服务端要识别客户的身份。使用Cookie是最简单的身从验证。
Cookie是web服务器存放在客户端的一个文件,客户端访问特定URL时会查询该文件,将与该URL相关的Cookie字段传输至服务端用作特定处理。Cookie可以设置失效时间,当Cookie过了失效时间后会自动消失不再随请求传输到服务器。
用户在登录成功或注册成功后随机生成一个ticket作为用户后续操作无需密码验证的凭证,往login_ticket表中插入一条记录将ticket与具体的用户绑定,这样用户在操作时候就能通过ticket凭证辨别身份。登录成功或注册成功后将ticket凭证放入Cookie,保存在用户浏览器中,在下次访问时候会随请求传输到服务器用作身份验证。
(1) 往login_ticket表中插入一条记录用于绑定ticket凭证和用户身份
public String addLoginTicket(int userId){LoginTicket loginTicket = new LoginTicket();loginTicket.setUserId(userId);Date date = new Date();date.setTime(date.getTime()+1000*3600*30);loginTicket.setExpired(date);loginTicket.setStatus(0);loginTicket.setTicket(UUID.randomUUID().toString().replaceAll("-",""));loginTicketDao.insertLoginTicket(loginTicket);return loginTicket.getTicket();
}
(2) 登录成功后将ticket凭证放入cookie,保存在用户浏览器;ticket有时效,过凭证期后用户需重新登录。
@RequestMapping("/login")public String login(Model model, HttpServletResponse httpResponse,@RequestParam String username,@RequestParam String password,@RequestParam(value = "next",required = false)String next){Map<String,String> map = userService.login(username,password);if (map.containsKey("ticket")) {Cookie cookie = new Cookie("ticket",map.get("ticket"));cookie.setPath("/");httpResponse.addCookie(cookie);if (StringUtils.isNotBlank(next)){return "redirect:"+next;}return "redirect:/";}else {model.addAttribute("msg", map.get("msg"));return "login";}}
(3) 注册成功后将ticket凭证放入cookie,保存在用户浏览器;ticket有时效,过凭证期后用户需重新登录。
@RequestMapping("/register")public String register(Model model, HttpServletResponse httpResponse,@RequestParam String username, @RequestParam String password,@RequestParam(value = "next",required = false)String next){Map<String,String> map = userService.register(username,password);if (map.containsKey("ticket")){Cookie cookie = new Cookie("ticket",map.get("ticket"));cookie.setPath("/");httpResponse.addCookie(cookie);if (StringUtils.isNotBlank(next))return "redirect:"+next;elsereturn "redirect:/";}else {model.addAttribute("msg",map.get("msg"));return "login";}}
5. 总结
系统的注册登录功能主要是将用户注册的用户名密码存储在数据库,在下次登录时进行比对。同时为了免密码登录,在登录成功或注册成功时后生成用户凭证ticket与用户身份绑定在一起放入cookie中,等用户下次访问时候随请求传输至服务器进行验证。这样就能直接根据凭证识别用户身份,无需再经过用户名密码的验证。
Spring boot 搭建个人博客系统(二)——登录注册功能相关推荐
- 基于Spring Boot+Vue的博客系统 16——热门文章功能简单的实现
废弃说明: 这个专栏的文章本意是记录笔者第一次搭建博客的过程,文章里里有很多地方的写法都不太恰当,现在已经废弃,关于SpringBoot + Vue 博客系列,笔者重新写了这个系列的文章,不敢说写的好 ...
- java 搭建个人博客_Spring boot 搭建个人博客系统(一)——整体思路
Spring boot 搭建个人博客系统(一)--整体思路 一直想用Spring boot 搭建一个属于自己的博客系统,刚好前段时间学习了叶神的牛客项目课受益匪浅,乘热打铁也主要是学习,好让自己熟悉这 ...
- 基于Spring Boot技术栈博客系统企业级前后端实战之课程导论(零)
零.说明(必读) 一.课程概述 1.1 名称 1.2 功能 1.3 技术点 1.4 目标 二.核心功能 2.1 用户管理 2.2 安全设置 2.3 博客管理 2.4 评论管理 2.5 点赞管理 2.6 ...
- 基于Spring Boot的个人博客系统(源码+数据库)
目录 一.系统功能框架图 二.开发技术 三.开发环境 四.页面展示 1.登录页面 2.首页 3.文章详情页面 4.文章评论页面 5.后台页面 6.后台文件编辑页面 7.后台文章管理列表页面 五.文 ...
- 基于Spring Boot的个人博客系统的设计与实现毕业设计源码271611
目 录 摘要 1 绪论 1.1研究意义 1.2开发背景 1.3系统开发技术的特色 1.4论文结构与章节安排 2个人博客系统系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1数据增加流程 ...
- halo java_Halo - 轻快,简洁,功能强大,使用Spring Boot开发的博客系统
Halo 是一款现代化的个人独立博客系统,给习惯写博客的同学多一个选择. 简介 Halo [ˈheɪloʊ],意为光环.当然,你也可以当成拼音读(哈喽). 一个优秀的开源博客发布应用,值得一试. 声明 ...
- 手把手带你搭建个人博客系统(二)
⭐️前言⭐️ 因文章篇幅较长,所以整个流程分两篇文章来完成.
- Spring MVC + Hibernate JPA + Bootstrap 搭建的博客系统
Spring MVC + Hibernate JPA + Bootstrap 搭建的博客系统 Demo 相关阅读: 1.Spring MVC+Hibernate JPA+ Bootstrap 搭建的博 ...
- 【Microsoft Azure 的1024种玩法】七十一.基于Azure Virtual Machines快速上手搭建Typecho博客系统
[简介] Typecho 是基于 PHP5 构建的开源跨平台博客系统,Typecho开源跨平台博客系统相较于wordpress .hexo有一定的性能优势,是我们记录文章内容的最佳首选博客,那么本篇文 ...
最新文章
- Unity Pro builder创建模块化仓库建筑学习教程
- mysql选择行_在mysql中选择特殊行
- mysql的show profile使用总结
- vue商城项目开发:axios发送请求及列表数据展示
- db2 最近三个月_昙花一现,PA、PC月跌1800,通用料一蹶不振,救不起的塑市!
- 【阿里云MPS】MPS(原MTS)概述
- 深度学习优化器 optimizer 的选择
- Teams数据统计 - 聊天消息
- 模仿mongodb采用xml+json实现小型数据库
- 人能为赚钱吃多少苦?
- 为什么说只有深度思考才能让你持续赚到钱?
- Nginx + php-fpm + PHP 5.4 + MySQL 5.5 + Zend
- iOS:实现邮件和短信发送的简单示例
- 驻云CEO教你0门槛搭建电商网站,精选产品组合限量神券 低价买
- 蚂蚁金服实习生4.16面试
- 传奇爆率你了解多少?传奇爆率小技巧
- Eclipse:Build not configured correctly问题
- 计算机工程师标准着装,工程师穿什么样的衣服才好看
- CSS3 盒子设置border和padding不撑开盒子
- 关于线性代数:方程组同解