1. 程式人生 > >淘淘商城59-SSO單點登入系統之使用者登入介面開發

淘淘商城59-SSO單點登入系統之使用者登入介面開發

目錄

1.分析介面文件

請求的url:/user/login

請求的方法:POST

引數:username、password。

返回值:json資料,使用TaotaoResult包含一個token。

2.登入介面實現

2.1登入分析

看介面文件感覺登入比較簡單....其實並不是這樣。

下面這個圖是單點登入系統登入時,登入要經歷的完整流程圖。

目前只需要實現到,將key:token,value:user以String型別存入redis,將token存入cookie中即可。

也就是這部分:

登入的處理流程:

  1. 登入頁面提交使用者名稱密碼。
  2. 登入成功後生成token。Token相當於原來的jsessionid,字串,可以使用uuid。
  3. 把使用者資訊儲存到redis。Key就是token,value就是TbUser物件轉換成json。
  4. 使用String型別儲存Session資訊。可以使用“字首:token”為key
  5. 設定key的過期時間。模擬Session的過期時間。一般半個小時。
  6. 把token寫入cookie中。
  7. Cookie需要跨域。例如www.taotao.com\sso.taotao.com\order.taotao.com,可以使用工具類。
  8. Cookie的有效期。關閉瀏覽器失效。
  9. 登入成功,進入portal首頁。

2.2服務層

2.2.1dao層

查詢tb_user表。直接使用逆向工程。

2.2.2service層

service介面

在taotao-sso-interface建立登入介面UserLoginService

/**
	 * 使用者登入,生成token作為key,value=user
	 * @param username
	 * @param password
	 * @return
	 */
	TaotaoResult login(String username,String password);

service實現類

  1. 判斷使用者名稱密碼是否正確。
  2. 登入成功後生成token。Token相當於原來的jsessionid,字串,可以使用uuid。
  3. 把使用者資訊儲存到redis。Key就是token,value就是TbUser物件轉換成json。
  4. 使用String型別儲存Session資訊。可以使用“字首:token”為key
  5. 設定key的過期時間。模擬Session的過期時間。一般半個小時。
  6. 返回TaotaoResult包裝token。

在taotao-sso-service建立實現類UserLoginServiceImpl

使用"字首:token"作為key,可以很好的分類redis中的存放的資料。字首和過期時間放在properties檔案中

package com.taotao.sso.service.impl;

import java.util.List;
import java.util.UUID;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import com.alibaba.dubbo.common.utils.StringUtils;
import com.taotao.common.pojo.TaotaoResult;
import com.taotao.common.utils.JsonUtils;
import com.taotao.mapper.TbUserMapper;
import com.taotao.pojo.TbUser;
import com.taotao.pojo.TbUserExample;
import com.taotao.pojo.TbUserExample.Criteria;
import com.taotao.sso.jedis.JedisClient;
import com.taotao.sso.service.UserLoginService;
@Service
public class UserLoginServiceImpl implements UserLoginService {
	
	@Autowired
	private TbUserMapper userMapper;
	@Autowired
	private JedisClient jedisClient;
	@Value("${USER_SESSION}")
	private String USER_SESSION;
	@Value("${SESSION_EXPIRE_TIME}")
	private Integer SESSION_EXPIRE_TIME;
	/**
	 * 校驗使用者名稱、密碼。校驗成功後生產token
	 * 把token作為key,將使用者資訊快取到redis中,並設定過期時間
	 */
	@Override
	public TaotaoResult login(String username, String password) {
		//1.校驗使用者名稱、密碼
		//1.1校驗使用者名稱是否存在
		TbUserExample tbUserExample = new TbUserExample();
		Criteria criteria = tbUserExample.createCriteria();
		criteria.andUsernameEqualTo(username);
		List<TbUser> list = userMapper.selectByExample(tbUserExample);
		if(list.size()==0 ||list==null) {
			return TaotaoResult.build(400, "使用者名稱或者密碼錯誤");
		}
		//1.2校驗密碼是否正確
		TbUser tbUser = list.get(0);
		if(!tbUser.getPassword().equals(DigestUtils.md5DigestAsHex(password.getBytes()))) {
			return TaotaoResult.build(400, "使用者名稱或者密碼錯誤");
		}
		//2.校驗成功後生產token
		String token = UUID.randomUUID().toString();
		//3.把使用者資訊儲存到redis。Key就是token,value就是TbUser物件轉換成json。
		tbUser.setPassword(null);
		String key = USER_SESSION + ":" +token;
		jedisClient.set(key, JsonUtils.objectToJson(tbUser));
		//4.設定token過期時間
		jedisClient.expire(key, SESSION_EXPIRE_TIME);
		//5.返回token
		return TaotaoResult.ok(token);
	}
}

resource.properties配置檔案

建立resource.properties放在taotao-sso-service的src/main/resources下

#redis中快取使用者資訊key的字首
USER_SESSION=SESSION
#session存活時間
SESSION_EXPIRE_TIME=1800

釋出服務

在applicationContext-service.xml中釋出服務

<dubbo:service interface="com.taotao.sso.service.UserLoginService" ref="userLoginServiceImpl" timeout="300000"/>

2.3表現層

2.3.1引入服務

在taotao-sso-web的springmvc.xml中引入service的服務

<dubbo:reference interface="com.taotao.sso.service.UserLoginService" id="userLoginService" timeout="300000" />
    

2.3.2controller

在這裡使用了一個CookieUtils用來專門將token存放到cookie中,cookie需要跨域。

將CookieUtils放到taotao-common裡面

package com.taotao.common.utils;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


/**
 * 
 * Cookie 工具類
 *
 */
public final class CookieUtils {

    /**
     * 得到Cookie的值, 不編碼
     * 
     * @param request
     * @param cookieName
     * @return
     */
    public static String getCookieValue(HttpServletRequest request, String cookieName) {
        return getCookieValue(request, cookieName, false);
    }

    /**
     * 得到Cookie的值,
     * 
     * @param request
     * @param cookieName
     * @return
     */
    public static String getCookieValue(HttpServletRequest request, String cookieName, boolean isDecoder) {
        Cookie[] cookieList = request.getCookies();
        if (cookieList == null || cookieName == null) {
            return null;
        }
        String retValue = null;
        try {
            for (int i = 0; i < cookieList.length; i++) {
                if (cookieList[i].getName().equals(cookieName)) {
                    if (isDecoder) {
                        retValue = URLDecoder.decode(cookieList[i].getValue(), "UTF-8");
                    } else {
                        retValue = cookieList[i].getValue();
                    }
                    break;
                }
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return retValue;
    }

    /**
     * 得到Cookie的值,
     * 
     * @param request
     * @param cookieName
     * @return
     */
    public static String getCookieValue(HttpServletRequest request, String cookieName, String encodeString) {
        Cookie[] cookieList = request.getCookies();
        if (cookieList == null || cookieName == null) {
            return null;
        }
        String retValue = null;
        try {
            for (int i = 0; i < cookieList.length; i++) {
                if (cookieList[i].getName().equals(cookieName)) {
                    retValue = URLDecoder.decode(cookieList[i].getValue(), encodeString);
                    break;
                }
            }
        } catch (UnsupportedEncodingException e) {
        	 e.printStackTrace();
        }
        return retValue;
    }

    /**
     * 設定Cookie的值 不設定生效時間預設瀏覽器關閉即失效,也不編碼
     */
    public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
            String cookieValue) {
        setCookie(request, response, cookieName, cookieValue, -1);
    }

    /**
     * 設定Cookie的值 在指定時間內生效,但不編碼
     */
    public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
            String cookieValue, int cookieMaxage) {
        setCookie(request, response, cookieName, cookieValue, cookieMaxage, false);
    }

    /**
     * 設定Cookie的值 不設定生效時間,但編碼
     */
    public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
            String cookieValue, boolean isEncode) {
        setCookie(request, response, cookieName, cookieValue, -1, isEncode);
    }

    /**
     * 設定Cookie的值 在指定時間內生效, 編碼引數
     */
    public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
            String cookieValue, int cookieMaxage, boolean isEncode) {
        doSetCookie(request, response, cookieName, cookieValue, cookieMaxage, isEncode);
    }

    /**
     * 設定Cookie的值 在指定時間內生效, 編碼引數(指定編碼)
     */
    public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
            String cookieValue, int cookieMaxage, String encodeString) {
        doSetCookie(request, response, cookieName, cookieValue, cookieMaxage, encodeString);
    }

    /**
     * 刪除Cookie帶cookie域名
     */
    public static void deleteCookie(HttpServletRequest request, HttpServletResponse response,
            String cookieName) {
        doSetCookie(request, response, cookieName, "", -1, false);
    }

    /**
     * 設定Cookie的值,並使其在指定時間內生效
     * 
     * @param cookieMaxage cookie生效的最大秒數
     */
    private static final void doSetCookie(HttpServletRequest request, HttpServletResponse response,
            String cookieName, String cookieValue, int cookieMaxage, boolean isEncode) {
        try {
            if (cookieValue == null) {
                cookieValue = "";
            } else if (isEncode) {
                cookieValue = URLEncoder.encode(cookieValue, "utf-8");
            }
            Cookie cookie = new Cookie(cookieName, cookieValue);
            if (cookieMaxage > 0)
                cookie.setMaxAge(cookieMaxage);
            if (null != request) {// 設定域名的cookie
            	String domainName = getDomainName(request);
            	//System.out.println(domainName);
                if (!"localhost".equals(domainName)) {
                	cookie.setDomain(domainName);
                }
            }
            cookie.setPath("/");
            response.addCookie(cookie);
        } catch (Exception e) {
        	 e.printStackTrace();
        }
    }

    /**
     * 設定Cookie的值,並使其在指定時間內生效
     * 
     * @param cookieMaxage cookie生效的最大秒數
     */
    private static final void doSetCookie(HttpServletRequest request, HttpServletResponse response,
            String cookieName, String cookieValue, int cookieMaxage, String encodeString) {
        try {
            if (cookieValue == null) {
                cookieValue = "";
            } else {
                cookieValue = URLEncoder.encode(cookieValue, encodeString);
            }
            Cookie cookie = new Cookie(cookieName, cookieValue);
            if (cookieMaxage > 0)
                cookie.setMaxAge(cookieMaxage);
            if (null != request) {// 設定域名的cookie
            	String domainName = getDomainName(request);
            	System.out.println(domainName);
                if (!"localhost".equals(domainName)) {
                	cookie.setDomain(domainName);
                }
            }
            cookie.setPath("/");
            response.addCookie(cookie);
        } catch (Exception e) {
        	 e.printStackTrace();
        }
    }

    /**
     * 得到cookie的域名
     */
    private static final String getDomainName(HttpServletRequest request) {
        String domainName = null;

        String serverName = request.getRequestURL().toString();
        if (serverName == null || serverName.equals("")) {
            domainName = "";
        } else {
            serverName = serverName.toLowerCase();
            serverName = serverName.substring(7);
            final int end = serverName.indexOf("/");
            serverName = serverName.substring(0, end);
            final String[] domains = serverName.split("\\.");
            int len = domains.length;
            if (len > 3) {
                // www.xxx.com.cn
                domainName = "." + domains[len - 3] + "." + domains[len - 2] + "." + domains[len - 1];
            } else if (len <= 3 && len > 1) {
                // xxx.com or xxx.cn
                domainName = "." + domains[len - 2] + "." + domains[len - 1];
            } else {
                domainName = serverName;
            }
        }

        if (domainName != null && domainName.indexOf(":") > 0) {
            String[] ary = domainName.split("\\:");
            domainName = ary[0];
        }
        return domainName;
    }

}

在taotao-sso-web下建立UserLoginController。

設定cookie時需要設定一個name,將這個name放到resource.properties

package com.taotao.sso.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.taotao.common.pojo.TaotaoResult;
import com.taotao.common.utils.CookieUtils;
import com.taotao.sso.service.UserLoginService;

@Controller
public class UserLoginController {

	@Autowired
	private UserLoginService userLoginService;
	@Value("${COOKIE_TOKEN_KEY}")
	private String COOKIE_TOKEN_KEY;
	/**
	 * 接收username、password,呼叫service服務
	 * 將返回的token存入cookie中
	 * @param username
	 * @param password
	 * @param request
	 * @param response
	 * @return
	 */
	@RequestMapping(value = "/user/login", method = RequestMethod.POST)
	@ResponseBody
	public TaotaoResult login(String username, String password, HttpServletRequest request,
			HttpServletResponse response) {
		// 1、接收兩個引數。
		// 2、呼叫Service進行登入。
		TaotaoResult result = userLoginService.login(username, password);
		// 3、從返回結果中取token,寫入cookie。Cookie要跨域。
		if(result.getStatus() == 200) {
			String token = result.getData().toString();
			CookieUtils.setCookie(request, response, COOKIE_TOKEN_KEY, token);
		}
		// 4、響應資料。Json資料。TaotaoResult,其中包含Token。
		return result;
	}
}

resource.properties檔案

COOKIE_TOKEN_KEY=COOKIE_TOKEN_KEY

3.測試訪問

安裝taotao-common、taotao-sso,啟動taotao-sso、taotao-sso-web

我們使用資料庫中已存在的username=123465、password=123456

 返回了我們生成的token

我們檢視redis,發現使用者資訊已經存入redis中