淘淘商城59-SSO單點登入系統之使用者登入介面開發
目錄
1.分析介面文件
請求的url:/user/login
請求的方法:POST
引數:username、password。
返回值:json資料,使用TaotaoResult包含一個token。
2.登入介面實現
2.1登入分析
看介面文件感覺登入比較簡單....其實並不是這樣。
下面這個圖是單點登入系統登入時,登入要經歷的完整流程圖。
目前只需要實現到,將key:token,value:user以String型別存入redis,將token存入cookie中即可。
也就是這部分:
登入的處理流程:
- 登入頁面提交使用者名稱密碼。
- 登入成功後生成token。Token相當於原來的jsessionid,字串,可以使用uuid。
- 把使用者資訊儲存到redis。Key就是token,value就是TbUser物件轉換成json。
- 使用String型別儲存Session資訊。可以使用“字首:token”為key
- 設定key的過期時間。模擬Session的過期時間。一般半個小時。
- 把token寫入cookie中。
- Cookie需要跨域。例如www.taotao.com\sso.taotao.com\order.taotao.com,可以使用工具類。
- Cookie的有效期。關閉瀏覽器失效。
- 登入成功,進入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實現類
- 判斷使用者名稱密碼是否正確。
- 登入成功後生成token。Token相當於原來的jsessionid,字串,可以使用uuid。
- 把使用者資訊儲存到redis。Key就是token,value就是TbUser物件轉換成json。
- 使用String型別儲存Session資訊。可以使用“字首:token”為key
- 設定key的過期時間。模擬Session的過期時間。一般半個小時。
- 返回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中