目錄
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中