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