`
zqjshiyingxiong
  • 浏览: 439933 次
  • 性别: Icon_minigender_1
  • 来自: 无锡
社区版块
存档分类
最新评论

please remember me(auto login)

阅读更多
“记住我”——用户自动登录的实现(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) {

}
}
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics