十三、WEBプロジェクトの開発はSessionとCookieを利用して登録検証と無登録を実現する
17032 ワード
(一)ケース背景紹介 まず申請する.本ケースは主にCookieがあるクライアントに対して、Cookieがないクライアントは参照して実行することができる.ここで使われているのは主に私たちのSession技術です. 一部のページでは、私たちが一度ログインすれば、しばらくはログインしなくてもいいです.ここのログイン免除はCookie技術です.(二)SessionとCookie紹介 の、JavaではHttpServiceletRequestを呼び出すgetSessionメソッド(trueをパラメータとして使用)作成します.Sessionが作成されると、サーバはそのSessionに対して一意のSession idを生成します.このSession idは、その後のリクエストで作成したSessionを再取得するために使用されます.Sessionが作成されると、Sessionに関連するメソッドを呼び出してSessionにコンテンツを追加することができますが、これらのコンテンツはサーバに保存されます.,クライアントに送信されるのはSessionidのみである.クライアントが要求を再送信すると、このSessionidが帯域化され、サーバが要求を受信すると、Sessionidに従って対応するSessionが見つかり、再使用されます.このようなプロセスこそ,ユーザの状態を維持することができる.セッションの生存期間:現在のブラウザが閉じられるとセッションは消えます(現在のページが閉じてもセッションは存在します).
2.Cookie HTTPは無状態のプロトコルであるため、サーバはネットワーク接続だけで顧客の身分を知ることができない.どうしようかな?クライアントに通行証を発行しましょう.一人一人、誰がアクセスしても自分の通行証を持っていなければなりません.これでサーバーはパスポートからお客様の身元を確認できます.これがCookieの仕組みです.Cookieは実際には小さなテキスト情報です.クライアントはサーバを要求し、サーバがユーザの状態を記録する必要がある場合はresponseを使用してクライアントブラウザにCookieを発行します.クライアントブラウザはCookieを保存します.ブラウザがウェブサイトを再要求すると、ブラウザは要求したウェブサイトをCookieとともにサーバに送信する.サーバはCookieをチェックし、ユーザの状態を認識します.サーバは必要に応じてCookieの内容を変更することもできます.(二)実装の詳細1.第一歩:ログインチェック(主にログインしたことがないまたはログインの期限切れのユーザーに使用される)
ここで注意したいのは、 (1)ログインに成功した後はユーザー情報をセッションに保存し、ログインしてからアクセスできるページ間でジャンプして使用する (2)ログインに成功した後は「remember」
2、第二歩、無上陸検証と無上陸(Springブロッカー使用)
ここで注意しなければならないのは、 (1)Sessionチェックを先に行い、Cookieチェックを行わなければならない.2つの順序が逆にならない.そうしないと、ログインしてからアクセスできるページ間をジャンプするときに、Cookieチェックを繰り返し、リソースを浪費する. (2)userIdを利用してデータベースを照会する場合はMybatisインタフェースを呼び出す必要があるが、インターセプタの実行中にSpringがコンテナに「SysUserDao」を注入していないため、このとき「@Autowired」注入はできず、「SpringContextHandler」で「SysUserDao」オブジェクトを取得する必要があり、「SpringContextHandler」について定義、SpringでBeanを取得する異なる方法を参照してください(3)
2.Cookie HTTPは無状態のプロトコルであるため、サーバはネットワーク接続だけで顧客の身分を知ることができない.どうしようかな?クライアントに通行証を発行しましょう.一人一人、誰がアクセスしても自分の通行証を持っていなければなりません.これでサーバーはパスポートからお客様の身元を確認できます.これがCookieの仕組みです.Cookieは実際には小さなテキスト情報です.クライアントはサーバを要求し、サーバがユーザの状態を記録する必要がある場合はresponseを使用してクライアントブラウザにCookieを発行します.クライアントブラウザはCookieを保存します.ブラウザがウェブサイトを再要求すると、ブラウザは要求したウェブサイトをCookieとともにサーバに送信する.サーバはCookieをチェックし、ユーザの状態を認識します.サーバは必要に応じてCookieの内容を変更することもできます.(二)実装の詳細1.第一歩:ログインチェック(主にログインしたことがないまたはログインの期限切れのユーザーに使用される)
package com.imooc.service.impl;
import com.imooc.bean.SysUser;
import com.imooc.constant.SessionKeyConst;
import com.imooc.constant.PageCodeEnum;
import com.imooc.dao.SysUserDao;
import com.imooc.dto.SysUserDto;
import com.imooc.service.LoginService;
import com.imooc.util.Md5Util;
import com.imooc.util.VerifyUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* @author **
* @date 2018/6/13 17:01
*/
@Service
public class LoginServiceImpl implements LoginService {
@Autowired
private SysUserDao sysUserDao;
@Override
public boolean validate(SysUserDto sysUserDto, RedirectAttributes redirectAttributes
, HttpServletRequest request, HttpServletResponse response) {
if (!VerifyUtil.validateUsername(sysUserDto.getUsername())){
redirectAttributes.addFlashAttribute(PageCodeEnum.KEY, PageCodeEnum.USERNAME_ERROR);
return false;
}
if (!VerifyUtil.validateUsername(sysUserDto.getPassword())){
redirectAttributes.addFlashAttribute(PageCodeEnum.KEY, PageCodeEnum.PASSWORD_ERROR);
return false;
}
SysUser sysUser = new SysUser();
BeanUtils.copyProperties(sysUserDto, sysUser);
List sysUserList = sysUserDao.selectUser(sysUser);
if (sysUserList.size() != 1){
redirectAttributes.addFlashAttribute(PageCodeEnum.KEY, PageCodeEnum.LOGIN_FAILURE);
return false;
}
redirectAttributes.addFlashAttribute(PageCodeEnum.KEY, PageCodeEnum.LOGIN_SUCCESS);
// Session ( !)
request.getSession().setAttribute(SessionKeyConst.SESSION_USER, sysUser);
// Session Cookie ( !)
if (sysUserDto.isRemember()){
SysUser user = sysUserList.get(0);
String loginToken = generateLoginToken(user.getUsername(), user.getPassword(), user.getId());
Cookie cookie = new Cookie(SessionKeyConst.SESSION_LOGIN_TOKEN, loginToken);
// path, “/login” cooke
cookie.setPath("/");
cookie.setMaxAge(SessionKeyConst.EXPIRE_TIME);
response.addCookie(cookie);
}
return true;
}
/**
* 、 id
* @param username
* @param password
* @param userId id
* @return
*/
public static String generateLoginToken(String username, String password, Integer userId) {
return Md5Util.getMD5WithSalt(username+password, SessionKeyConst.ENCRYPT_SALT) + ":" + userId;
}
}
ここで注意したいのは、 (1)ログインに成功した後はユーザー情報をセッションに保存し、ログインしてからアクセスできるページ間でジャンプして使用する (2)ログインに成功した後は「remember」
“md5( ,md5( )): ID”
がCookieに書き込まれているかどうかを判断するために識別される.Tokenの構成方法について、原理を簡単に説明します.“:”
でTokenを切断することでユーザidを得ることができ、データベースに行って対応するユーザを検索し、データベースのユーザ名、パスワードをmd 5塩値で暗号化し、転送されたTokenと比較し、等しく検証することができます. (3)Cookieを設定する際、必要に応じてCookieの有効期間を設定し、登録をどのくらい免除できるかを決定します.(4)Cookieを設定するときは、状況に応じてCookieのpathを設定しなければなりません.どの経路にアクセスするかを決定するとき、ゲスト側がアクセスするときにCookieを転送するからです.2、第二歩、無上陸検証と無上陸(Springブロッカー使用)
package com.imooc.interceptor;
import com.imooc.bean.SysUser;
import com.imooc.constant.SessionKeyConst;
import com.imooc.dao.SysUserDao;
import com.imooc.util.Md5Util;
import com.imooc.util.SpringContextHolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* Session, (HandlerInterceptor Spring , JDK )
* @author **
* @date 2018/6/13 11:37
*/
public class SessionInterceptor implements HandlerInterceptor {
private static final Logger LOGGER = LoggerFactory.getLogger(SessionInterceptor.class);
/**
* Handler ( Controller )
* @return true: , , Controller Handler
* false: afterCompletion() , , Handler
*/
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
HttpSession session = httpServletRequest.getSession();
// Session User, ,
if (session.getAttribute(SessionKeyConst.SESSION_USER) != null){
return true;
}
// Cookie
if (validateLoginWithCookie(httpServletRequest)){
return true;
}
// Session User, ,
httpServletRequest.getRequestDispatcher("/login/sessionTimeout").forward(httpServletRequest, httpServletResponse);
return false;
}
private boolean validateLoginWithCookie(HttpServletRequest httpServletRequest) {
String loginToken = "";
Cookie[] cookies = httpServletRequest.getCookies();
if (cookies != null && cookies.length >0){
for (Cookie cookie : cookies){
if (SessionKeyConst.SESSION_LOGIN_TOKEN.equals(cookie.getName())){
loginToken = cookie.getValue();
}
}
}
if (!loginToken.trim().equals("")){
// userId
String[] strs = loginToken.split(":");
String md5Str = strs[0];
String userId = strs[1];
// ,SysUserDao Spring , @AutoWired SysUserDao
SysUserDao sysUserDao = SpringContextHolder.getBean(SysUserDao.class);
SysUser sysUser = sysUserDao.selectUserWithId(Integer.parseInt(userId));
if (sysUser != null){
// ,LoginServiceImpl Spring , token ,
String str = Md5Util.getMD5WithSalt(sysUser.getUsername()+sysUser.getPassword(), SessionKeyConst.ENCRYPT_SALT);
// ,
if (md5Str.equals(str)){
// Session, ( , !!)
httpServletRequest.getSession().setAttribute(SessionKeyConst.SESSION_USER, sysUser);
return true;
}
}
}
return false;
}
/**
* Handler , ModelAndView ( Handler )
*/
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
/**
* Handler
*/
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
ここで注意しなければならないのは、 (1)Sessionチェックを先に行い、Cookieチェックを行わなければならない.2つの順序が逆にならない.そうしないと、ログインしてからアクセスできるページ間をジャンプするときに、Cookieチェックを繰り返し、リソースを浪費する. (2)userIdを利用してデータベースを照会する場合はMybatisインタフェースを呼び出す必要があるが、インターセプタの実行中にSpringがコンテナに「SysUserDao」を注入していないため、このとき「@Autowired」注入はできず、「SpringContextHandler」で「SysUserDao」オブジェクトを取得する必要があり、「SpringContextHandler」について定義、SpringでBeanを取得する異なる方法を参照してください(3)
"/login/sessionTimeout"
は、私がControllerで集中的に検証を処理するのに成功せず、再ログインする必要があるエントリです.(4)ユーザーがパスワードを変更すると、ユーザーに強制的に終了し、再ログインする必要があります.クライアントのTokenは依然として古いTokenなので、古いTokenを新しいものに変更する必要があります.