前后端交互实战:从零搭建登录系统
1. 登录系统基础架构设计登录系统是每个Web应用的基石就像小区门禁系统一样既要保证合法用户顺利通行又要拦截非法访问。我们先来看一个典型的登录流程用户在表单输入账号密码 - 前端校验数据格式 - 后端验证凭证 - 返回登录结果。这个过程中涉及三个关键组件前端界面负责收集用户输入后端服务处理业务逻辑数据库存储用户凭证我建议采用分层架构设计这样后期维护会更方便。比如把数据库操作单独封装成DAO层业务逻辑放在Service层。实际项目中我遇到过把所有代码都写在Servlet里的情况后期改个密码加密方式都要翻遍所有文件那叫一个痛苦。2. 前端表单开发实战2.1 HTML表单构建先创建一个最简单的登录页面重点注意这三个属性form action/api/login methodpost enctypeapplication/x-www-form-urlencoded input typetext nameusername required input typepassword namepassword minlength6 button typesubmit登录/button /formaction属性要指向后端接口URLmethod用POST更安全。我在早期项目里犯过用GET传密码的低级错误结果密码全显示在浏览器地址栏里...2.2 前端数据校验别完全依赖后端校验前端应该先做基本验证document.querySelector(form).addEventListener(submit, (e) { const pwd document.querySelector([namepassword]).value if(pwd.length 6) { e.preventDefault() alert(密码至少6位) } })推荐使用HTML5原生验证属性如required、pattern比手动写JS验证更高效。实测下来合理使用这些属性能减少30%以上的非法请求。3. 后端接口开发3.1 Servlet基础配置创建LoginServlet需要继承HttpServlet注意要重写doPost方法而非doGetWebServlet(/api/login) public class LoginServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) { String username request.getParameter(username); // 业务处理... } }现在更推荐用WebServlet注解替代web.xml配置代码更简洁。但老项目维护时还是会遇到xml配置所以两种方式最好都掌握。3.2 密码安全处理千万不能明文存储密码应该这样处理// 密码加密 String hashedPwd BCrypt.hashpw(rawPassword, BCrypt.gensalt()); // 密码验证 if(BCrypt.checkpw(inputPassword, storedHash)) { // 登录成功 }我踩过的坑早期项目用MD5加密结果被彩虹表轻松破解。现在推荐用bcrypt或PBKDF2这类带盐值的哈希算法。4. 数据库交互设计4.1 用户表设计建议至少包含这些字段CREATE TABLE users ( id BIGINT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) UNIQUE NOT NULL, password_hash CHAR(60) NOT NULL, # bcrypt结果固定60位 status TINYINT DEFAULT 1, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );特别注意要给username加唯一索引否则会出现重复账号。曾经有个项目没加索引结果用户注册时总提示账号已存在查了半天才发现是并发问题。4.2 使用PreparedStatement防止SQL注入的正确姿势String sql SELECT * FROM users WHERE username ?; PreparedStatement stmt conn.prepareStatement(sql); stmt.setString(1, username); ResultSet rs stmt.executeQuery();注意参数索引从1开始这个细节坑过不少新手。另外记得要在finally块里关闭连接否则连接泄露会导致数据库崩溃。5. 会话管理与安全控制5.1 Cookie与Session登录成功后要建立会话HttpSession session request.getSession(); session.setAttribute(user, username); // 设置会话超时30分钟 session.setMaxInactiveInterval(1800);浏览器关闭后session不会立即失效这点和很多人想的不一样。实际过期时间取决于服务器配置建议显式设置。5.2 过滤器实现权限控制用过滤器做登录检查public class AuthFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) { HttpServletRequest request (HttpServletRequest) req; HttpSession session request.getSession(false); if(session null || session.getAttribute(user) null) { ((HttpServletResponse)res).sendRedirect(/login); } else { chain.doFilter(req, res); } } }注意要排除登录页面和静态资源否则会陷入重定向循环。我见过最夸张的案例是过滤器配置错误导致CSS文件都要登录才能访问。6. 实战中的常见问题6.1 跨域问题处理如果前后端分离开发会遇到跨域问题。解决方案response.setHeader(Access-Control-Allow-Origin, http://localhost:3000); response.setHeader(Access-Control-Allow-Credentials, true);记得生产环境要把Allow-Origin改成具体的域名不要直接用*否则会有安全风险。6.2 密码重置功能这个功能容易被忽视但很重要// 生成重置令牌 String token UUID.randomUUID().toString(); // 存入数据库并设置15分钟过期 redisTemplate.opsForValue().set(reset:token, username, 15, TimeUnit.MINUTES);令牌要设置合理的过期时间我建议15-30分钟。太短影响用户体验太长增加安全风险。7. 性能优化技巧7.1 数据库连接池别每次都新建连接用连接池// Tomcat配置示例 Resource namejdbc/UserDB authContainer typejavax.sql.DataSource maxTotal20 maxIdle10 maxWaitMillis10000 usernamedbuser passworddbpass driverClassNamecom.mysql.cj.jdbc.Driver urljdbc:mysql://localhost:3306/userdb/连接数不是越多越好一般建议是CPU核心数的2-3倍。设置太大反而会导致性能下降。7.2 缓存登录状态频繁查数据库会影响性能可以用Redis缓存// 登录成功后缓存用户信息 redisTemplate.opsForValue().set(user:username, userData, 30, TimeUnit.MINUTES);缓存时间建议和session超时时间一致。注意缓存雪崩问题可以加个随机偏移量。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2440740.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!