please remember me(auto login)

2023-11-16

“记住我”——用户自动登录的实现(auto login)

一、什么是用户自动登录?

对于我们的网站向已注册用户提供某些专门的服务,比如网上购物、在线下载、收费浏览等等,就会要求用户在使用这些服务之前进入登录页面,输入用户名和密码,并进行验证。

如果用户经常访问我们的网站,假如每天都访问一次,或者好几次,那么用户每次都重复这些登录操作就会感到相当厌烦。通过一些简单的技术手段,我们可以让网站“记住”那些在曾经登录过的用户。当该用户下次再来访问的时候,网站可以识别该用户,并为其自动完成登录过程。

二、基本思路

作为网站的编写者,我们无从知道坐在电脑前的那个人是谁。我们能够知道的是,访问网站的是哪一台电脑——这一点可以通过Cookie实现。因此,对用户的识别实际上就是对客户端电脑的识别。

简单的说,当用户第一次登录网站的时候,网站向客户端发送一个包含有用户名的Cookie。当用户在之后的某个时候再次访问,浏览器就会向网站服务器回送这个Cookie,于是,我们可以从这个Cookie中读取到用户名,然后调用登录的方法,从而实现自动为用户登录。

三、防止欺骗

Cookie只是一个普通的文本文件,那里面包含的字符串可以直接用记事本打开并进行编辑。因此任何人在任何电脑上都可以伪造一个包含有他人用户名的 Cookie,从而实现对他人身份的冒用。要解决这个问题,就要在Cookie中附加一项信息,这个信息需要具有以下特性:1、和该用户一一对应;2、伪造难度大。这些内容和用户名一起,以Cookie的形式发送给用户的浏览器。并且,服务器必须能够记住这项内容,以便用户再次访问的时候进行核对。

理论上,可以使用该用户的密码。密码具备了前述的两个特点。但是因为Cookie本身未经加密,保存于其中的密码可以被任何人看到,因此这个方法极不安全。

另一种可以加以利用的信息是用户访问时的Session id。因为Session id是一个由系统随机产生的、无规律的、长度较长的字符串,因此它很难被伪造。要把它和用户对应起来,我们需要在数据库中添加一个表,这个表至少有两个字段,一个是用户名,一个是Session id。当用户首次登录的时候,我们把当前的Session id和用户名分别用Cookie发送给用户,同时,把这两项作为一条记录插入数据库。这样,当用户再次访问的时候,服务器就可以读取客户端发来的这两个 Cookie,并且用它们的值和数据库中的记录比对。如果在数据库中找到了相应记录,就说明这台电脑的确是该用户上次登录时使用的电脑,进而可以为该用户自动登录。

四、实现

1、在登录页面中添加一个复选框,让用户选择是否愿意在一定时间内实现自动登陆,例如两周。

代码:
<input type="checkbox" name="autologin">两周内自动登录

2、在负责处理登录过程的Servlet中,判断用户是否选择了该复选框。如果是,则执行这两个操作:向用户发送两个Cookie,以及向数据库写入一条相应的记录。

代码:

Cookie ckUsername, ckSessionid;

if (autologin.equals("on")) {
// 如果用户选择了“两周内自动登录”,则向用户发送两个cookie。
// 一个cookie记录用户名,另一个记录唯一的验证码,
// 并将此验证码写入数据库,以备用户返回时查询。(防止伪造cookie)
ckUsername = new Cookie("autoLoginUser", user.getUsername()); // user是代表用户的bean
ckUsername.setMaxAge(60 * 60 * 24 * 14); //设置Cookie有效期为14天
res.addCookie(ckUsername);

sessionid = session.getId(); // 取得当前的session id
ckSessionid = new Cookie("sessionid", sessionid);
ckSessionid.setMaxAge(60 * 60 * 24 * 14);
res.addCookie(ckSessionid);

// 在数据库中插入相应记录
userSessionDAO.insertUserSession(user, sessionid);
}
可能还需要加入时间字段,要看系统的需求而定。

3、实现自动登录。因为用户下次访问的时候,可能直接访问网站的任何页面(例如通过收藏夹),而不一定是首页或者登录页面,所以我们需要用Filter拦截到达该网站的所有请求,并执行自动登录。

public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
HttpSession session = request.getSession(true);
String username;
String sessionid; // 此sessionid是上次用户登录时保存于用户端的识别码,用于用户后续访问的自动登录。不是本次访问的session id。
Cookie[] cookies;
CookieManager cm = new CookieManager(); // CookieManager是一个自定义的类,用于从Cookie数组中查找并返回指定名称的Cookie值。
boolean isAutoLogin;

// 如果session中没有user对象,则创建一个。
User user = (User) session.getAttribute("user");
if (user == null) {
user = new User(); // 此时user中的username属性为"",表示用户未登录。
}

// 如果user对象的username为"",表示用户未登录。则执行自动登录过程。
// 否则不自动登录。
if (user.getUsername().equals("")) {
// 检查用户浏览器是否发送了上次登录的用户名和sessionid,
// 如果是,则为用户自动登陆。
cookies = request.getCookies();
username = cm.getCookieValue(cookies, "autoLoginUser");
sessionid = cm.getCookieValue(cookies, "sessionid");
isAutoLogin = userSessionDAO.getAutoLoginState(username, sessionid); // 如果在数据库中找到了相应记录,则说明可以自动登录。

if (isAutoLogin) {
user.setUsername(username);
user.setNickname(DBUtil.getNickName(username));
session.setAttribute("user", user); // 将user bean添加到session中。
}
}
chain.doFilter(req, resp);
}
以上代码只是一个实例,不同的框架,需要修改。但基本都是通过SERVLET继续处理。这里需要在FILTER中调用业务方法(可以加入下面的方法):
private UserSessionDAO getAuthService(HttpServletRequest httpRequest) {
WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(httpRequest.getSession().getServletContext());
return (UserSessionDAO)webApplicationContext.getBean("userSessionDAO");
}

4、注销。只有当用户在上次访问时,未经注销就离开网站,我们才能在该用户下次访问时执行自动登录。如果用户显式的执行了注销操作,那就表示该用户不希望我们记住他。我们需要在执行注销操作的Servlet中,从数据库中删除相应记录。这样,下次用户访问的时候就不会执行自动登录了。



五、改进

用户可能为了方便,自行修改Cookie中的有效期,从而达到长期自动登录的目的。对某些存有敏感信息的网站来说,这样做并不安全。当用户长时间没有使用他的电脑,或者将电脑遗弃、转让了,而保存于其中的Cookie仍然是有效的,这就为用户和网站带来潜在的风险。

要解决这个问题,我们可以在数据库中增加一个字段,用以记录自动登录的过期日。这样,是否执行自动登录就不再以客户端的Cookie有效期为准,而是以服务器端数据库中的信息为准。当我们想要调整用户自动登录的有效期的时候,只需要修改数据库中相应的日期字段即可,因而这一过程变得更加安全。

这里再提供一个添加COOKIES的JAVA类:

public class CookieUtils
{
public CookieUtils()
{
}

/**
* 根据Cookie名称得到Cookie的值,没有返回Null
*
* 2006-7-28
* @param request
* @param name
* @return
*/
public static String getCookieValue(HttpServletRequest request, String name)
{
Cookie cookie = getCookie(request, name);
if (cookie != null)
{
return cookie.getValue();
}
else
{
return null;
}
}

/**
* 根据Cookie名称得到Cookie对象,不存在该对象则返回Null
*
* 2006-7-28
* @param request
* @param name
* @return
*/
public static Cookie getCookie(HttpServletRequest request, String name)
{
Cookie cookies[] = request.getCookies();
if (cookies == null || name == null || name.length() == 0)
return null;
Cookie cookie = null;
for (int i = 0; i < cookies.length; i++)
{
if (!cookies[i].getName().equals(name))
continue;
cookie = cookies[i];
if (request.getServerName().equals(cookie.getDomain()))
break;
}

return cookie;
}

/**
* 删除指定Cookie
*
* 2006-7-28
* @param response
* @param cookie
*/
public static void deleteCookie(HttpServletResponse response, Cookie cookie)
{
if (cookie != null)
{
cookie.setPath("/");
cookie.setValue("");
cookie.setMaxAge(0);
response.addCookie(cookie);
}
}

/**
* 删除指定Cookie
*
* 2006-7-28
* @param response
* @param cookie
*/
public static void deleteCookie(HttpServletResponse response, Cookie cookie,String domain)
{
if (cookie != null)
{
cookie.setPath("/");
cookie.setValue("");
cookie.setMaxAge(0);
cookie.setDomain(domain);
response.addCookie(cookie);
}
}

/**
* 添加一条新的Cookie信息,默认有效时间为一个月
*
* 2006-7-28
* @param response
* @param name
* @param value
* @param maxAge
*/
public static void setCookie(HttpServletResponse response, String name, String value)
{
setCookie(response, name, value, 0x278d00);
}

/**
* 添加一条新的Cookie信息,可以设置其最长有效时间(单位:秒)
*
* 2006-7-28
* @param response
* @param name
* @param value
* @param maxAge
*/
public static void setCookie(HttpServletResponse response, String name, String value, int maxAge)
{
if (value == null)
value = "";
Cookie cookie = new Cookie(name, value);
cookie.setMaxAge(maxAge);
cookie.setPath("/");
response.addCookie(cookie);
}

/**
* 添加一条新的Cookie信息,可以设置其Name,Value,MaxAge,Path,Domain(单位:秒)
*
* 2006-8-23
* @param response
* @param name
* @param value
* @param maxAge
*/
public static void setCookie(
HttpServletResponse response,
String name,
String value,
int maxAge,
String path,
String domain)
{
if (value == null)
value = "";
Cookie cookie = new Cookie(name, value);
cookie.setMaxAge(maxAge);
cookie.setPath(path);
cookie.setDomain(domain);
response.addCookie(cookie);
}

public static void main(String[] args) {

}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

please remember me(auto login) 的相关文章

  • 在springboot 中配置使用servlet

    文章目录 1 前言 2 servlet 3 springboot配置 4 启动项目 5 UrlMapping设置 6 Filter 7 Listener 8 总结 1 前言 还记得 说到web项目 最早接触的就是servlet 实际上SSH
  • Get,Post请求中文乱码问题有效解决方法

    对于做Java WEB项目同学来说 中文乱码问题是一个经常遇到而又非常头痛的问题 而最容易出现乱码的环节就是在浏览器向服务器发送请求的过程 至于出现乱码的原因不是本文的关注的重点 想了解的朋友可以参考 http zhaomin819111
  • 写需求分析必须牢记的5大要点

    需求验证的5大要点 要做好需求验证 必须在思想 方法 语言 人员 内容5个要点上做好相应的工作 否则就会产生很多负面的影响 1 思想 前面已经说过 由于Review被翻译成 评审 导致很多人将其与中国人常说的评审相混淆 其实它们之间是有区别
  • servlet实现文件上传

    上传文件满足条件 1 需要有个表单 表单里面有个input类型为file的上传域 2 请求方法必须是POST 3 表单需要添加enctype属性 Content Type multipart form data 告知服务器提交数据的MIME
  • MyBatis 学习笔记(四)---源码分析篇---配置文件的解析过程(一)

    概述 前几篇我们介绍了MyBatis的一些基本特性 对MyBatis有了个初步了解 接下来 我们将着手来分析一下MyBatis的源码 从源码层面复盘MyBatis的执行流程 思维导图概括 配置文件解析过程分析 有了上述思维导图 我们对配置文
  • Web前端开发概述

    Web World Wide Web 全球广域网 是指一种基于互联网的信息系统 通过超文本链接将全球各地的文档 图像 视频等资源相互关联起来 并通过Web浏览器进行交互浏览和访问 Web的发展使得人们可以方便地获取和共享各种类型的信息 成为
  • spring Bean 生命周期BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean接口详解

    继续接着上一篇完成后续接口的解析 还是借用上一篇引用大佬的文章 https www jianshu com p 1dec08d290c1 第二篇spring Bean 生命周期及BeanPostProcessor和Instantiation
  • Spring(三):JavaBean的生命周期

    JavaBean的生命周期 一 基本概念 bean 就是由IOC 容器初始化 装配及管理的对象 Spring中的bean默认都是单例的 那么单例Bean在多线程程序下如何保证线程安全呢 Spring的单例是基于BeanFactory也就是S
  • Swagget技术·SpringBoot继承Swagger框架详解!

    文章目录 一 Swagger简介 二 SpringBoot集成Swagger 三 配置Swagger 1 Swagger实例Bean是Docket 所以通过配置Docket实例来配置Swaggger 2 可以通过apiInfo 属性配置文档
  • Servlet 和 Cookie-Session 学习笔记(基础)

    简单来说 是运行在服务器端的 Java 程序 它作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层 用处 使用 Servlet 您可以收集来自网页表单的用户输入 呈现来自数据库或者其他
  • java复制文件后保持文件的创建时间不变

    复制后保持文件的创建时间不变 File oldFile new File E test old png File newFile new File E test new png FileCopyUtils copy oldFile newF
  • STC仿真失败

    原因就是购买的下载工具不适合在烧写STC8H3K64S仿真固件后再将该下载工具作为USB转串口工具连接PC与目标板 推测是接入仿真时会重启目标板 不打算细究 换一个普通串口就好了
  • 10分钟带你了解轻量级插件框架x3py

    写在前面 由于本人目前主要从事的是Windows客户端开发方面的工作 所以本文介绍x3py的侧重点也是从客户端程序开发者方面叙述的 本文主要参考整理自x3py的官方Wiki 修正了一些官方示例中的错误 有兴趣的同学可以直接阅读原文 设计目的
  • 值得学习与推荐的c/c++框架和函数库

    这几天不上班 翻翻Evernote中记录的一些笔记 刚好有时间把记录的一些好玩链接转载一下 这篇文章里提到的很多库都用过 尤其是图像处理相关库 尤其是opencv及cximage 当时做图像算法时 很多算法就是从上面找来 然后自己修改的 比
  • Spring IoC依赖注入的实现

    看了 spring技术内幕 的第二章 学习了spring的IoC容器的实现 对其做了浅显地分析 依赖注入的时机 如果配置文件有配置lazy init 那么依赖注入的时机发生在用户向IoC 容器索取bean的时候 即调用beanfactory
  • 跨域与跨域访问

    什么是跨域 跨域是指从一个域名的网页去请求另一个域名的资源 比如从www baidu com 页面去请求 www google com 的资源 跨域的严格一点的定义是 只要 协议 域名 端口有任何一个的不同 就被当作是跨域 为什么浏览器要限
  • JAVA 8 新特性及使用

    1 前言 2019年9月19日java13已正式发布 感叹java社区强大 经久不衰 由于国内偏保守 新东西总要放一放 让其他人踩踩坑 等稳定了才会去用 并且企业目的还是赚钱 更不会因为一个新特性去重构代码 再开发一套程序出来 甚者国内大多
  • 数学建模——论文排版

    目录 一 参考文献的排版 1 三种方案 通常使用方案一 方案一有两种方法 2 参考文献排版要点总结 二 附录的排版 具体方法 补充 代码高亮 三 表格标题自动编号 进阶做法 四 公式编辑软件的介绍 1 LaTeX 较难 有时间可学 2 wo
  • JavaWeb——第五章 Servlet

    第五章 Servlet 一 Servlet简介 1 1 动态资源和静态资源 1 2 Servlet简介 二 Servlet开发流程 2 1 目标 2 2 开发过程 三 Servlet注解方式配置
  • JavaWeb——第五章 Servlet

    第五章 Servlet 一 Servlet简介 1 1 动态资源和静态资源 1 2 Servlet简介 二 Servlet开发流程 2 1 目标 2 2 开发过程 三 Servlet注解方式配置

随机推荐

  • 【mac】Obsidian手动安装插件-多端同步

    手动插件安装 porxy github 这个插件是专门解决 无法加载插件市场的 先在github中打开链接 github上教了方法 下载zip文件 解压后 插入到 obsidian plugins文件夹内 一般来讲 小白刚安装的时候难免找不
  • CentOS7 Hive2.3.9 安装部署(mysql 8.0)

    一 CentOS7安装MySQL数据库 查询载mariadb rpm qa grep mariadb 卸载mariadb rpm e nodeps 查询出来的内容 安装wget为下载mysql准备 yum y install wget 在t
  • mysql alter的用法--修改表,字段等信息

    一 修改表信息 1 修改表名 修改表名为studen1 alter table student rename to student1 2 修改表注释 修改表注释 alter table student comment 学生表 二 修改字段信
  • Python-字典合并

    方法1 使用update方法 第二个参数合并第一个参数 def merge dict1 dict2 return dict2 update dict1 两个字典 dict1 a 10 b 8 dict2 d 6 c 4 返回None pri
  • Python入门必背代码大全

    前言 Python作为一门简洁而强大的编程语言 广泛应用于数据分析 Web开发 人工智能等领域 本文将为您整理一份Python入门必背的代码大全 帮助您掌握常用的Python代码片段 快速入门并提升编程技能 一 基本语法和数据类型操作 打印
  • C++的类与对象

    类的概念 类是将不同类型的数据和处理这些数据的操作封装在一起的一个复合数据类型 类有两类成员 一类是数据成员 用于表示实体抽象的属性 另一类是成员函数 用来描述实体抽象的行为 类作为一种数据类型 在定义的时候是不分配内存的 类通过将数据和对
  • JVM OOM问题排查与解决思路

    OOM原因 1 堆溢出 报错信息 java lang OutOfMemoryError Java heap space 代码中可能存在大对象分配 无法获得足够的内存分配 可能发生内存泄露 导致内存被无效占用以至于耗尽 2 永久代 元空间溢出
  • Blender图解教程:新手入门练习1

    多边形建模命令仅在编辑模式下可用 一 台灯 成果展示 步骤 1 打开Blender 新建 常规 文件 2 制作台灯底座 选择该立方体的上面 快捷键 3 然后使用快捷键 G 再按快捷键 Z 使其沿Z轴移动 移动鼠标 调整台灯底座到合适的高度
  • 电脑提示d3dcompiler_47.dll丢失怎么解决?d3dcompiler_47.dll缺失修复方法

    d3dcompiler 47 dll文件是Windows系统重要的组件 电脑一出现缺失或者损坏的情况下 电脑很多游戏跟软件都无法打开运行 小编今天就把修复教程分享给大家 首先是打开电脑浏览器后在顶部输入 dll修复文件 site 按下键盘的
  • 两个有序链表序列的合并(省略函数实现)

    浙大版 数据结构 第2版 题目集 习题2 5 两个有序链表序列的合并 include
  • 华为OD机试 Python 需要打开多少监控器

    描述 想象一下 你在一个长方形停车场 每个车位正上方都有一个监控器 只有当车位上或其周围 前 后 左 右 有车时 这个监控器才会开启 请根据给定的停车场车辆分布 计算需要开启的监控器数量 输入 第一行 两个整数 分别表示停车场的长和宽 1
  • C++学习(六十三)指针数组和数组指针

    指针数组 类似整型数组 浮点型数组 指数组里的元素为指针 define ARRAY LEN 100 char myStrPtr ARRAY LEN char指针的数组 墨菲定律的几条推论 会出错的事 总会出错 世上没有绝对正确的事情 每个解
  • Hashmap源码详解

    在开发中的对于数据结构如何选 我们要知道各个数据结构的优缺点 数组 采用一段连续的存储单元来存储数据 对于指定下标的查找 时间复杂度为O 1 但在数组中间以及头部插入数据时 需要复制移动后面的元素O n 优点 查找快 缺点插入慢 链表 一种
  • xmind怎么在左边创建_XMind如何调整分支主题位置?XMind分支主题任意移动方法

    如何利用xmind制作自己的思维导图 你好 建议你可以这样试试看 打开画图工具点击上方栏目 思维导图 在跳转专的页面点击 立即属体验 进入在线绘制界面 在画布的四周有很多的工具栏 这些在绘制的过程中都是可以使用的 首先 将中心主题进行确立
  • 使用 docker 搭建 clickhouse 集群

    转载来自 blog miaoji io p 57 写在前面 你好 欢迎浏览我的博客 这篇文章将记录我使用docker搭建clickhouse集群的过程 工具准备 服务器准备 这里我们准备三台服务器 分别配置hostname为server01
  • SpringBoot中静态资源文件的存放位置

    1 静态资源路径是指系统可以直接访问的路径 且路径下的所有文件均可被用户 通过浏览器直接读取 2 在Springboot中默认的静态资源路径有 classpath META INF resources classpath resources
  • 微信小程序——组件库

    文章目录 WeUI ColorUI LinUI echarts for weixin WeUI WeUI是微信官方设计团队为微信Web开发量身打造的一个UI样式库 可以理解为一种类似于Bootstrap的前端UI库 使用WeUI来编写小程序
  • rosrun 和 roslaunch 的时候 TAB 的自动补全出现问题

    rosrun 和 roslaunch 的时候 TAB 的自动补全出现问题 rospack Warning error while crawling home sun boost filesystem status Permission de
  • javaRebel(jRebel)使用手记

    想必大家对项目开发中 调试类文件修改时 容器自动重新加载漫长的过程早已厌倦 我今天闲来无事 于是 想试试javaRebel jRebel 这个东西 javaRebel jRebel 现在是收费软件 不过在网上可以下载到确解版的 在网上查了一
  • please remember me(auto login)

    记住我 用户自动登录的实现 auto login 一 什么是用户自动登录 对于我们的网站向已注册用户提供某些专门的服务 比如网上购物 在线下载 收费浏览等等 就会要求用户在使用这些服务之前进入登录页面 输入用户名和密码 并进行验证 如果用户