十三、WEBプロジェクトの開発はSessionとCookieを利用して登録検証と無登録を実現する


(一)ケース背景紹介  まず申請する.本ケースは主に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.第一歩:ログインチェック(主にログインしたことがないまたはログインの期限切れのユーザーに使用される)
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を新しいものに変更する必要があります.