目录
1. 单点登录系统分析
1.1. 什么是SSO
SSO英文全称Single Sign On,单点登录。SSO是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。它包括可以将这次主要的登录映射到其他应用中用于同一个用户的登录的机制。它是目前比较流行的企业业务整合的解决方案之一。
1.2. 原来的登录逻辑实现
1.2.1. 问题
单台tomcat,以上实现是没有任何问题的,但是我们现在是集群的tomcat,就会存在session共享问题。
只要解决session共享问题,登录问题即可解决。
每个系统都有自己的session,不能统一。
1.2.2. 解决session共享问方案
1、 tomcat的session复制
优点:不需要额外开发,只需要搭建tomcat集群即可。
缺点:tomcat 是全局session复制,集群内每个tomcat的session完全同步(也就是任何时候都完全一样的) 在大规模应用的时候,用户过多,集群内tomcat数量过多,session的全局复制会导致集群性能下降, 因此,tomcat的数量不能太多,5个以下为好。
2、 实现单点登录系统,提供服务接口。把session数据存放在redis。
Redis可以设置key的生存时间、访问速度快效率高。
优点:redis存取速度快,不会出现多个节点session复制的问题。效率高。
缺点:需要程序员开发。
1.3 单点登录系统的流程
2. SSO开发
单点登录系统是一个独立的系统,需要操作redis,连接数据库
2.1. 系统架构
2.2. 开发SSO服务
2.2.1.1. 创建sso服务工程
所需要的技术
mybatis,需要依赖taotao-manager-mapper
spring
springmvc
Pom.xml
Pom.xml文件参考taotao-rest工程的pom文件。
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.taotao</groupId>
<artifactId>taotao-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>com.taotao</groupId>
<artifactId>taotao-sso</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<!-- 依赖taotao-manager-mapper工程 -->
<dependency>
<groupId>com.taotao</groupId>
<artifactId>taotao-manager-mapper</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- MySql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<!-- Redis客户端 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<!-- solr客户端 -->
<dependency>
<groupId>org.apache.solr</groupId>
<artifactId>solr-solrj</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 配置Tomcat插件 -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<configuration>
<port>8084</port>
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
</project>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<display-name>taotao-sso</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list><!-- 加载spring容器 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/applicationContext-*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 解决post乱码 -->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- springmvc的前端控制器 -->
<servlet>
<servlet-name>taotao-sso</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- contextConfigLocation不是必须的, 如果不配置contextConfigLocation, springmvc的配置文件默认在:WEB-INF/servlet的name+"-servlet.xml" -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>taotao-sso</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
2.2.1.2框架整合
SqlMapConfig.xml
保留
db.properties
保留
resource.properties
清空内容
applicationContext-dao.xml
保留
applicationContext-jedis.xml
修改文件,并创建相关包
applicationContext-service.xml
修改,并创建相关包
applicationContext-trans.xml
springmvc.xml
修改,并创建相关包
2.2.1.3. 服务开发
a) 登录接口
b) 注册接口
c) 查询接口
d) 退出登录接口
开发的流程:
1、 确定流程、确定接口内容
2、 提供接口文档
a) 接口地址
b) 入参说明
c) 接口访问方式,get、post
d) 结果输出,说明格式
e) 接口调用的示例
3、 约定联合测试的时间点
4、 发布上线
参考:SSO接口文档.docx
2.3 开发注册接口
1、 需要对用户提交的数据做校验
2、 对密码做md5加密
3、 对报错异常要做处理
2.3.1. 数据校验接口
请求方法 | GET |
---|---|
URL | http://sso.taotao.com/user/check/{param}/{type} |
参数说明 | 格式如:zhangsan/ 1,其中zhangsan是校验的数据,type为类型,可选参数1、2、3分别代表username、phone、email 可选参数callback:如果有此参数表示此方法为jsonp请求,需要支持jsonp。 |
示例 | http://sso.taotao.com/user/check/zhangsan/1 |
返回值 | { status: 200 //200 成功 msg: “OK” // 返回信息消息 data: false // 返回数据,true:数据可用,false:数据不可用 } |
2.3.1.1 dao
对tb_user表进行单表查询。使用逆向工程生成的mapper即可。
2.3.1.2 Service
接受两个参数:内容、内容类型
根据内容类型查询tb_user表返回taotaoresult对象
UserService.java
/taotao-sso/src/main/java/com/taotao/sso/service/UserService.java
package com.taotao.sso.service;
import com.taotao.common.utill.TaotaoResult;
/**
* 用户管理
* @author Lenovo
*
*/
public interface UserService {
// 数据校验
TaotaoResult checkData(String content,Integer type);
}
UserServiceImpl.java
/taotao-sso/src/main/java/com/taotao/sso/service/impl/UserServiceImpl.java
package com.taotao.sso.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.taotao.common.utill.TaotaoResult;
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.service.UserService;
/**
* 用户管理
*
* @author Lenovo
*
*/
@Service
public class UserServiceImpl implements UserService {
@Autowired
private TbUserMapper userMapper;
// 数据校验
@Override
public TaotaoResult checkData(String content, Integer type) {
//创建查询条件
TbUserExample example = new TbUserExample();
Criteria criteria = example.createCriteria();
//对数据进行校验:1、2、3分别代表username、phone、email
//用户名校验
if (1 == type) {
criteria.andUsernameEqualTo(content);
//电话校验
} else if ( 2 == type) {
criteria.andPhoneEqualTo(content);
//email校验
} else {
criteria.andEmailEqualTo(content);
}
//执行查询
List<TbUser> list = userMapper.selectByExample(example);
if (list == null || list.size() == 0) {
return TaotaoResult.ok(true);
}
return TaotaoResult.ok(false);
}
}
2.3.1.3 controller
从url中接受两个参数,调用service进行校验,在调用service之前,先对参数进行校验
UserController.java
/taotao-sso/src/main/java/com/taotao/sso/controller/UserController.java
package com.taotao.sso.controller;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.converter.json.MappingJacksonValue;
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.ResponseBody;
import com.taotao.common.utill.ExceptionUtil;
import com.taotao.common.utill.TaotaoResult;
import com.taotao.sso.service.UserService;
/**
* 用户管理
*
* @author Lenovo
*/
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/check/{param}/{type}")
@ResponseBody
public Object checkData(@PathVariable String param, @PathVariable Integer type, String callback) {
TaotaoResult result = null;
// 参数有效性校验
if (StringUtils.isBlank(param)) {
result = TaotaoResult.build(400, "校验内容不能为空");
}
if (type == null) {
result = TaotaoResult.build(400, "校验内容类型不能为空");
}
if (type != 1 && type != 2 && type != 3) {
result = TaotaoResult.build(400, "校验内容类型错误");
}
// 校验出错
if (null != result) {
if (null != callback) {
MappingJacksonValue mappingJacksonValue = new MappingJacksonValue(result);
mappingJacksonValue.setJsonpFunction(callback);
return mappingJacksonValue;
} else {
return result;
}
}
// 调用服务
try {
result = userService.checkData(param, type);
} catch (Exception e) {
result = TaotaoResult.build(500, ExceptionUtil.getStackTrace(e));
}
if (null != callback) {
MappingJacksonValue mappingJacksonValue = new MappingJacksonValue(result);
mappingJacksonValue.setJsonpFunction(callback);
return mappingJacksonValue;
} else {
return result;
}
}
}
2.3.1.4 测试
通过tb_user表查找
http://localhost:8084/check/zhangsan/1
http://localhost:8084/user/check/aa@a/3
http://localhost:8084/user/check/12/4
2.3.2 用户注册接口
请求方法 | POST |
---|---|
URL | http://sso.taotao.com/user/register |
参数 | username //用户名 password //密码 phone //手机号 email //邮箱 |
参数说明 | |
示例 | http://sso.taotao.com/user/register |
返回值 | { status: 400 msg: “注册失败. 请校验数据后请再提交数据.” data: null } |
2.3.2.1 dao
使用逆向工程生成的mapper即可。
2.3.2.2 Service
接受tbUser对象,补全user的属性。向tb_user表插入记录。返回taotaoResult
UserService.java
/taotao-sso/src/main/java/com/taotao/sso/service/UserService.java
package com.taotao.sso.service;
import com.taotao.common.utill.TaotaoResult;
import com.taotao.pojo.TbUser;
/**
* 用户管理
* @author Lenovo
*
*/
public interface UserService {
// 数据校验接口
TaotaoResult checkData(String content,Integer type);
// 用户注册接口
TaotaoResult createUser(TbUser user);
}
UserServiceImpl.java
/taotao-sso/src/main/java/com/taotao/sso/service/impl/UserServiceImpl.java
package com.taotao.sso.service.impl;
import java.util.Date;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import com.taotao.common.utill.TaotaoResult;
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.service.UserService;
/**
* 用户管理
*
* @author Lenovo
*
*/
@Service
public class UserServiceImpl implements UserService {
@Autowired
private TbUserMapper userMapper;
// 数据校验接口
@Override
public TaotaoResult checkData(String content, Integer type) {
//创建查询条件
TbUserExample example = new TbUserExample();
Criteria criteria = example.createCriteria();
//对数据进行校验:1、2、3分别代表username、phone、email
//用户名校验
if (1 == type) {
criteria.andUsernameEqualTo(content);
//电话校验
} else if ( 2 == type) {
criteria.andPhoneEqualTo(content);
//email校验
} else {
criteria.andEmailEqualTo(content);
}
//执行查询
List<TbUser> list = userMapper.selectByExample(example);
if (list == null || list.size() == 0) {
return TaotaoResult.ok(true);
}
return TaotaoResult.ok(false);
}
// 用户注册接口
@Override
public TaotaoResult createUser(TbUser user) {
user.setUpdated(new Date());
user.setCreated(new Date());
//md5加密
user.setPassword(DigestUtils.md5DigestAsHex(user.getPassword().getBytes()));
userMapper.insert(user);
return TaotaoResult.ok();
}
}
2.3.2.3 controller
接受提交的数据用户名、密码、电话、邮件、使用pojo接接收,使用tbuser。调用service向表中添加记录。返回taotaoresult
UserController.java
/taotao-sso/src/main/java/com/taotao/sso/controller/UserController.java
package com.taotao.sso.controller;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.converter.json.MappingJacksonValue;
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.utill.ExceptionUtil;
import com.taotao.common.utill.TaotaoResult;
import com.taotao.pojo.TbUser;
import com.taotao.sso.service.UserService;
/**
* 用户管理
*
* @author Lenovo
*/
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
// 数据校验接口
@RequestMapping("/check/{param}/{type}")
@ResponseBody
public Object checkData(@PathVariable String param, @PathVariable Integer type, String callback) {
TaotaoResult result = null;
// 参数有效性校验
if (StringUtils.isBlank(param)) {
result = TaotaoResult.build(400, "校验内容不能为空");
}
if (type == null) {
result = TaotaoResult.build(400, "校验内容类型不能为空");
}
if (type != 1 && type != 2 && type != 3) {
result = TaotaoResult.build(400, "校验内容类型错误");
}
// 校验出错
if (null != result) {
if (null != callback) {
MappingJacksonValue mappingJacksonValue = new MappingJacksonValue(result);
mappingJacksonValue.setJsonpFunction(callback);
return mappingJacksonValue;
} else {
return result;
}
}
// 调用服务
try {
result = userService.checkData(param, type);
} catch (Exception e) {
result = TaotaoResult.build(500, ExceptionUtil.getStackTrace(e));
}
if (null != callback) {
MappingJacksonValue mappingJacksonValue = new MappingJacksonValue(result);
mappingJacksonValue.setJsonpFunction(callback);
return mappingJacksonValue;
} else {
return result;
}
}
// 用户注册接口
@RequestMapping(value="/register", method=RequestMethod.POST)
@ResponseBody
public TaotaoResult createUser(TbUser user) {
try {
TaotaoResult result = userService.createUser(user);
return result;
} catch (Exception e) {
e.printStackTrace();
return TaotaoResult.build(500, ExceptionUtil.getStackTrace(e));
}
}
}
2.4 用户登录接口
请求方法 | POST |
---|---|
URL | http://sso.taotao.com/user/login |
参数 | username //用户名 password //密码 |
参数说明 | |
示例 | http://sso.taotao.com/user/login username=zhangsan&password=123 |
返回值 | { status: 200 msg: “OK” data: “fe5cb546aeb3ce1bf37abcb08a40493e” //登录成功,返回token } |
根据用户名查询用户信息,查到之后进行密码对比,需要对密码进行md5加密后进行对比,比对成功后即可登录成功,需要生成一个token可以使用uuid,需要把用户信息写入redis,key就是token,value就是用户信息,返回token字符串
2.4.1 dao
查询数据库tb_user表,根据用户名查询用户信息
2.4.2 Service
接受tbUser对象,补全user的属性。向tb_user表插入记录。返回taotaoResult
UserService.java
/taotao-sso/src/main/java/com/taotao/sso/service/UserService.java
package com.taotao.sso.service;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.taotao.common.utill.TaotaoResult;
import com.taotao.pojo.TbUser;
/**
* 用户管理
* @author Lenovo
*
*/
public interface UserService {
// 数据校验接口
TaotaoResult checkData(String content,Integer type);
// 用户注册接口
TaotaoResult createUser(TbUser user);
// 用户登录接口
TaotaoResult userLogin(String username, String password);
}
UserServiceImpl.java
/taotao-sso/src/main/java/com/taotao/sso/service/impl/UserServiceImpl.java
package com.taotao.sso.service.impl;
import java.util.Date;
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.taotao.common.utill.JsonUtils;
import com.taotao.common.utill.TaotaoResult;
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.dao.JedisClient;
import com.taotao.sso.service.UserService;
/**
* 用户管理
*
* @author Lenovo
*
*/
@Service
public class UserServiceImpl implements UserService {
@Autowired
private TbUserMapper userMapper;
@Autowired
private JedisClient jedisClient;
@Value("${REDIS_USER_SESSION_KEY}")
private String REDIS_USER_SESSION_KEY;
@Value("${SSO_SESSION_EXPIRE}")
private Integer SSO_SESSION_EXPIRE;
// 数据校验接口
@Override
public TaotaoResult checkData(String content, Integer type) {
//创建查询条件
TbUserExample example = new TbUserExample();
Criteria criteria = example.createCriteria();
//对数据进行校验:1、2、3分别代表username、phone、email
//用户名校验
if (1 == type) {
criteria.andUsernameEqualTo(content);
//电话校验
} else if ( 2 == type) {
criteria.andPhoneEqualTo(content);
//email校验
} else {
criteria.andEmailEqualTo(content);
}
//执行查询
List<TbUser> list = userMapper.selectByExample(example);
if (list == null || list.size() == 0) {
return TaotaoResult.ok(true);
}
return TaotaoResult.ok(false);
}
// 用户注册接口
@Override
public TaotaoResult createUser(TbUser user) {
user.setUpdated(new Date());
user.setCreated(new Date());
//md5加密
user.setPassword(DigestUtils.md5DigestAsHex(user.getPassword().getBytes()));
userMapper.insert(user);
return TaotaoResult.ok();
}
// 用户登录接口
@Override
public TaotaoResult userLogin(String username, String password) {
TbUserExample example = new TbUserExample();
Criteria criteria = example.createCriteria();
criteria.andUsernameEqualTo(username);
List<TbUser> list = userMapper.selectByExample(example);
//如果没有此用户名
if (null == list || list.size() == 0) {
return TaotaoResult.build(400, "用户名或密码错误");
}
TbUser user = list.get(0);
//比对密码
if (!DigestUtils.md5DigestAsHex(password.getBytes()).equals(user.getPassword())) {
return TaotaoResult.build(400, "用户名或密码错误");
}
//生成token
String token = UUID.randomUUID().toString();
//保存用户之前,把用户对象中的密码清空。
user.setPassword(null);
//把用户信息写入redis
jedisClient.set(REDIS_USER_SESSION_KEY + ":" + token, JsonUtils.objectToJson(user));
//设置session的过期时间
jedisClient.expire(REDIS_USER_SESSION_KEY + ":" + token, SSO_SESSION_EXPIRE);
//返回token
return TaotaoResult.ok(token);
}
}
resource.properties
/taotao-sso/src/main/resources/resource/resource.properties
#用戶session在redis中保存的key
REDIS_USER_SESSION_KEY=REDIS_USER_SESSION
#session的过期时间
SSO_SESSION_EXPIRE=1800
2.4.3 controller
接受提交的数据用户名、密码。调用service向表中添加记录。
UserController.java
/taotao-sso/src/main/java/com/taotao/sso/controller/UserController.java
package com.taotao.sso.controller;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.converter.json.MappingJacksonValue;
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.utill.ExceptionUtil;
import com.taotao.common.utill.TaotaoResult;
import com.taotao.pojo.TbUser;
import com.taotao.sso.service.UserService;
/**
* 用户管理
*
* @author Lenovo
*/
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
// 数据校验接口
@RequestMapping("/check/{param}/{type}")
@ResponseBody
public Object checkData(@PathVariable String param, @PathVariable Integer type, String callback) {
TaotaoResult result = null;
// 参数有效性校验
if (StringUtils.isBlank(param)) {
result = TaotaoResult.build(400, "校验内容不能为空");
}
if (type == null) {
result = TaotaoResult.build(400, "校验内容类型不能为空");
}
if (type != 1 && type != 2 && type != 3) {
result = TaotaoResult.build(400, "校验内容类型错误");
}
// 校验出错
if (null != result) {
if (null != callback) {
MappingJacksonValue mappingJacksonValue = new MappingJacksonValue(result);
mappingJacksonValue.setJsonpFunction(callback);
return mappingJacksonValue;
} else {
return result;
}
}
// 调用服务
try {
result = userService.checkData(param, type);
} catch (Exception e) {
result = TaotaoResult.build(500, ExceptionUtil.getStackTrace(e));
}
if (null != callback) {
MappingJacksonValue mappingJacksonValue = new MappingJacksonValue(result);
mappingJacksonValue.setJsonpFunction(callback);
return mappingJacksonValue;
} else {
return result;
}
}
// 用户注册接口
@RequestMapping(value="/register", method=RequestMethod.POST)
@ResponseBody
public TaotaoResult createUser(TbUser user) {
try {
TaotaoResult result = userService.createUser(user);
return result;
} catch (Exception e) {
e.printStackTrace();
return TaotaoResult.build(500, ExceptionUtil.getStackTrace(e));
}
}
// 用户登录接口
@RequestMapping(value="/login", method=RequestMethod.POST)
@ResponseBody
public TaotaoResult userLogin(String username, String password) {
try {
TaotaoResult result = userService.userLogin(username, password, request, response);
return result;
} catch (Exception e) {
e.printStackTrace();
return TaotaoResult.build(500, ExceptionUtil.getStackTrace(e));
}
}
}
2.5 根据token查询用户
请求方法 | GET |
---|---|
URL | http://sso.taotao.com/user/token/{token} |
参数 | token //用户登录凭证 callback//jsonp回调方法 |
参数说明 | 可选参数callback:如果有此参数表示此方法为jsonp请求,需要支持jsonp。 |
示例 | http://sso.taotao.com/user/token/fe5cb546aeb3ce1bf37abcb08a40493e |
返回值 | { status: 200 msg: “OK” data: “{“id”:1,“username”:“zhangzhijun”,“phone”:“15800807944”, “email”:“420840806@qq.com”,“created”:1414119176000,“updated”:1414119179000}” } |
2.5.1业务分析
根据token判断用户是否登录或者session是否过期。接受token,根据token对redis中取用户信息
判断token字符串是否对应用户信息,如果不对应说明token非法或者session已过期。取到了说明用户就是正常的登录状态。
返回用户信息,同时重置用户的过期时间
2.5.2 dao层
2.5.3 server层
接受token,调用dao到redis中查询token对应的用户信息
返回用户信息并更新过期时间
UserService.java
/taotao-sso/src/main/java/com/taotao/sso/service/UserService.java
package com.taotao.sso.service;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.taotao.common.utill.TaotaoResult;
import com.taotao.pojo.TbUser;
/**
* 用户管理
* @author Lenovo
*
*/
public interface UserService {
// 数据校验接口
TaotaoResult checkData(String content,Integer type);
// 用户注册接口
TaotaoResult createUser(TbUser user);
// 用户登录接口
TaotaoResult userLogin(String username, String password);
// 根据token查询用户
TaotaoResult getUserByToken(String token);
}
UserServiceImpl.java
/taotao-sso/src/main/java/com/taotao/sso/service/impl/UserServiceImpl.java
package com.taotao.sso.service.impl;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import org.apache.commons.lang3.StringUtils;
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.taotao.common.utill.JsonUtils;
import com.taotao.common.utill.TaotaoResult;
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.dao.JedisClient;
import com.taotao.sso.service.UserService;
/**
* 用户管理
*
* @author Lenovo
*
*/
@Service
public class UserServiceImpl implements UserService {
@Autowired
private TbUserMapper userMapper;
@Autowired
private JedisClient jedisClient;
@Value("${REDIS_USER_SESSION_KEY}")
private String REDIS_USER_SESSION_KEY;
@Value("${SSO_SESSION_EXPIRE}")
private Integer SSO_SESSION_EXPIRE;
// 数据校验接口
@Override
public TaotaoResult checkData(String content, Integer type) {
//创建查询条件
TbUserExample example = new TbUserExample();
Criteria criteria = example.createCriteria();
//对数据进行校验:1、2、3分别代表username、phone、email
//用户名校验
if (1 == type) {
criteria.andUsernameEqualTo(content);
//电话校验
} else if ( 2 == type) {
criteria.andPhoneEqualTo(content);
//email校验
} else {
criteria.andEmailEqualTo(content);
}
//执行查询
List<TbUser> list = userMapper.selectByExample(example);
if (list == null || list.size() == 0) {
return TaotaoResult.ok(true);
}
return TaotaoResult.ok(false);
}
// 用户注册接口
@Override
public TaotaoResult createUser(TbUser user) {
user.setUpdated(new Date());
user.setCreated(new Date());
//md5加密
user.setPassword(DigestUtils.md5DigestAsHex(user.getPassword().getBytes()));
userMapper.insert(user);
return TaotaoResult.ok();
}
// 用户登录接口
@Override
public TaotaoResult userLogin(String username, String password) {
TbUserExample example = new TbUserExample();
Criteria criteria = example.createCriteria();
criteria.andUsernameEqualTo(username);
List<TbUser> list = userMapper.selectByExample(example);
//如果没有此用户名
if (null == list || list.size() == 0) {
return TaotaoResult.build(400, "用户名或密码错误");
}
TbUser user = list.get(0);
//比对密码
if (!DigestUtils.md5DigestAsHex(password.getBytes()).equals(user.getPassword())) {
return TaotaoResult.build(400, "用户名或密码错误");
}
//生成token
String token = UUID.randomUUID().toString();
//保存用户之前,把用户对象中的密码清空。
user.setPassword(null);
//把用户信息写入redis
jedisClient.set(REDIS_USER_SESSION_KEY + ":" + token, JsonUtils.objectToJson(user));
//设置session的过期时间
jedisClient.expire(REDIS_USER_SESSION_KEY + ":" + token, SSO_SESSION_EXPIRE);
//返回token
return TaotaoResult.ok(token);
}
// 根据token查询用户
@Override
public TaotaoResult getUserByToken(String token) {
//根据token从redis中查询用户信息
String json = jedisClient.get(REDIS_USER_SESSION_KEY + ":" + token);
//判断是否为空
if (StringUtils.isBlank(json)) {
return TaotaoResult.build(400, "此session已经过期,请重新登录");
}
//更新过期时间
jedisClient.expire(REDIS_USER_SESSION_KEY + ":" + token, SSO_SESSION_EXPIRE);
//返回用户信息
return TaotaoResult.ok(JsonUtils.jsonToPojo(json, TbUser.class));
}
}
2.5.4 controller
接受token调用session返回用户信息,使用taotaoresult包装,
UserController.java
/taotao-sso/src/main/java/com/taotao/sso/controller/UserController.java
package com.taotao.sso.controller;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.converter.json.MappingJacksonValue;
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.utill.ExceptionUtil;
import com.taotao.common.utill.TaotaoResult;
import com.taotao.pojo.TbUser;
import com.taotao.sso.service.UserService;
/**
* 用户管理
*
* @author Lenovo
*/
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
// 数据校验接口
@RequestMapping("/check/{param}/{type}")
@ResponseBody
public Object checkData(@PathVariable String param, @PathVariable Integer type, String callback) {
TaotaoResult result = null;
// 参数有效性校验
if (StringUtils.isBlank(param)) {
result = TaotaoResult.build(400, "校验内容不能为空");
}
if (type == null) {
result = TaotaoResult.build(400, "校验内容类型不能为空");
}
if (type != 1 && type != 2 && type != 3) {
result = TaotaoResult.build(400, "校验内容类型错误");
}
// 校验出错
if (null != result) {
if (null != callback) {
MappingJacksonValue mappingJacksonValue = new MappingJacksonValue(result);
mappingJacksonValue.setJsonpFunction(callback);
return mappingJacksonValue;
} else {
return result;
}
}
// 调用服务
try {
result = userService.checkData(param, type);
} catch (Exception e) {
result = TaotaoResult.build(500, ExceptionUtil.getStackTrace(e));
}
if (null != callback) {
MappingJacksonValue mappingJacksonValue = new MappingJacksonValue(result);
mappingJacksonValue.setJsonpFunction(callback);
return mappingJacksonValue;
} else {
return result;
}
}
// 用户注册接口
@RequestMapping(value="/register", method=RequestMethod.POST)
@ResponseBody
public TaotaoResult createUser(TbUser user) {
try {
TaotaoResult result = userService.createUser(user);
return result;
} catch (Exception e) {
e.printStackTrace();
return TaotaoResult.build(500, ExceptionUtil.getStackTrace(e));
}
}
// 用户登录接口
@RequestMapping(value="/login", method=RequestMethod.POST)
@ResponseBody
public TaotaoResult userLogin(String username, String password) {
try {
TaotaoResult result = userService.userLogin(username, password, request, response);
return result;
} catch (Exception e) {
e.printStackTrace();
return TaotaoResult.build(500, ExceptionUtil.getStackTrace(e));
}
}
// 根据token查询用户
@RequestMapping("/token/{token}")
@ResponseBody
public Object getUserByToken(@PathVariable String token, String callback) {
TaotaoResult result = null;
try {
result = userService.getUserByToken(token);
} catch (Exception e) {
e.printStackTrace();
result = TaotaoResult.build(500, ExceptionUtil.getStackTrace(e));
}
//判断是否为jsonp调用
if (StringUtils.isBlank(callback)) {
return result;
} else {
MappingJacksonValue mappingJacksonValue = new MappingJacksonValue(result);
mappingJacksonValue.setJsonpFunction(callback);
return mappingJacksonValue;
}
}
}
3 用户注册
3.1 静态页面
springmvc.xml
/taotao-sso/src/main/resources/spring/springmvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan
base-package="com.taotao.sso.controller" />
<mvc:annotation-driven />
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<!-- 资源映射 -->
<mvc:resources location="/WEB-INF/css/" mapping="/css/**" />
<mvc:resources location="/WEB-INF/js/" mapping="/js/**" />
<mvc:resources location="/WEB-INF/images/" mapping="/images/**" />
</beans>
3.2 页面跳转
PageController.java
/taotao-sso/src/main/java/com/taotao/sso/controller/PageController.java
package com.taotao.sso.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* 页面跳转Controller
* @author Lenovo
*
*/
@Controller
@RequestMapping("/page")
public class PageController {
@RequestMapping("/register")
public String showRegister() {
return "register";
}
}
http://localhost:8084/page/register
3.3. 需求分析
用户注册时需要调用taotao-sso的服务检查用户的有效性以及用户、手机是否存在。检查通过后提交表单至taotao-portal的controller,由taotao-portal调用taotao-sso的服务注册用户。
进行用户注册之前先进行数据的有效验证:
用户名不能重复;
确认密码和密码文本框内容的一致
用户名、密码不能为空
手机号不能为空,不能重复
4 用户登录
4.1 页面跳转
PageController.java
/taotao-sso/src/main/java/com/taotao/sso/controller/PageController.java
package com.taotao.sso.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* 页面跳转Controller
* @author Lenovo
*
*/
@Controller
@RequestMapping("/page")
public class PageController {
// 注册页面
@RequestMapping("/register")
public String showRegister() {
return "register";
}
// 用户登录
@RequestMapping("/login")
public String showLogin() {
return "login";
}
}
http://localhost:8084/page/login
4.2 用户注册和用户登录的转跳
login.jsp
/taotao-sso/src/main/webapp/WEB-INF/jsp/login.jsp
register.jsp
/taotao-sso/src/main/webapp/WEB-INF/jsp/register.jsp
4.3 需求分析
login.jsp
/taotao-sso/src/main/webapp/WEB-INF/jsp/login.jsp
4.4登录页面回调url
回调url应该是一个参数传递给显示页面的controller
参数名redirect
需要把回调的url传递给jsp页面。
当登陆成功后,js的逻辑中判断是否有回调的url,如果有就跳转到此url,如果没有就跳转到商城首页
PageController.java
/taotao-sso/src/main/java/com/taotao/sso/controller/PageController.java
package com.taotao.sso.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* 页面跳转Controller
* @author Lenovo
*
*/
@Controller
@RequestMapping("/page")
public class PageController {
// 注册页面
@RequestMapping("/register")
public String showRegister() {
return "register";
}
// 用户登录
@RequestMapping("/login")
public String showLogin(String redirect, Model model) {
model.addAttribute("redirect", redirect);
return "login";
}
}
4.5 taotao-portal项目的登录和注册
header.jsp
/taotao-portal/src/main/webapp/WEB-INF/jsp/commons/header.jsp
shortcut.jsp
/taotao-portal/src/main/webapp/WEB-INF/jsp/commons/shortcut.jsp
base-v1.js
/taotao-portal/src/main/webapp/js/base-v1.js
5 使用拦截器实现用户登录
5.1 门户系统整合sso
在门户系统中点击登录连接转跳到登录页面。登录成功后,跳转到门户系统的首页,在门户系统中需要从cookie中把taken取出来,所以必须在登录成功后把token写入cookie,并且cookie的值必须在系统之间共享
5.1.1cookie共享:
-
domain:必须是相同的
需要设置domain为:taotao.com
-
设置path为:/
如果是localhost,不要设置domain,直接设置path即可
5.1.2工具类CookieUtils.java
CookieUtils.java
添加工具类
/taotao-common/src/main/java/com/taotao/common/utill/CookieUtils.java
package com.taotao.common.utill;
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;
}
}
pom.xml
/taotao-common/pom.xml
添加依赖
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<scope>provided</scope>
</dependency>
5.1.3 登录接口
UserService.java
/taotao-sso/src/main/java/com/taotao/sso/service/UserService.java
package com.taotao.sso.service;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.taotao.common.utill.TaotaoResult;
import com.taotao.pojo.TbUser;
/**
* 用户管理
* @author Lenovo
*
*/
public interface UserService {
// 数据校验接口
TaotaoResult checkData(String content,Integer type);
// 用户注册接口
TaotaoResult createUser(TbUser user);
// 用户登录接口
TaotaoResult userLogin(String username, String password, HttpServletRequest request, HttpServletResponse response);
// 根据token查询用户
TaotaoResult getUserByToken(String token);
}
UserServiceImpl.java
/taotao-sso/src/main/java/com/taotao/sso/service/impl/UserServiceImpl.java
package com.taotao.sso.service.impl;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
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.taotao.common.utill.JsonUtils;
import com.taotao.common.utill.TaotaoResult;
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.dao.JedisClient;
import com.taotao.sso.service.UserService;
/**
* 用户管理
*
* @author Lenovo
*
*/
@Service
public class UserServiceImpl implements UserService {
@Autowired
private TbUserMapper userMapper;
@Autowired
private JedisClient jedisClient;
@Value("${REDIS_USER_SESSION_KEY}")
private String REDIS_USER_SESSION_KEY;
@Value("${SSO_SESSION_EXPIRE}")
private Integer SSO_SESSION_EXPIRE;
// 数据校验接口
@Override
public TaotaoResult checkData(String content, Integer type) {
//创建查询条件
TbUserExample example = new TbUserExample();
Criteria criteria = example.createCriteria();
//对数据进行校验:1、2、3分别代表username、phone、email
//用户名校验
if (1 == type) {
criteria.andUsernameEqualTo(content);
//电话校验
} else if ( 2 == type) {
criteria.andPhoneEqualTo(content);
//email校验
} else {
criteria.andEmailEqualTo(content);
}
//执行查询
List<TbUser> list = userMapper.selectByExample(example);
if (list == null || list.size() == 0) {
return TaotaoResult.ok(true);
}
return TaotaoResult.ok(false);
}
// 用户注册接口
@Override
public TaotaoResult createUser(TbUser user) {
user.setUpdated(new Date());
user.setCreated(new Date());
//md5加密
user.setPassword(DigestUtils.md5DigestAsHex(user.getPassword().getBytes()));
userMapper.insert(user);
return TaotaoResult.ok();
}
// 用户登录接口
@Override
public TaotaoResult userLogin(String username, String password,
HttpServletRequest request, HttpServletResponse response) {
TbUserExample example = new TbUserExample();
Criteria criteria = example.createCriteria();
criteria.andUsernameEqualTo(username);
List<TbUser> list = userMapper.selectByExample(example);
//如果没有此用户名
if (null == list || list.size() == 0) {
return TaotaoResult.build(400, "用户名或密码错误");
}
TbUser user = list.get(0);
//比对密码
if (!DigestUtils.md5DigestAsHex(password.getBytes()).equals(user.getPassword())) {
return TaotaoResult.build(400, "用户名或密码错误");
}
//生成token
String token = UUID.randomUUID().toString();
//保存用户之前,把用户对象中的密码清空。
user.setPassword(null);
//把用户信息写入redis
jedisClient.set(REDIS_USER_SESSION_KEY + ":" + token, JsonUtils.objectToJson(user));
//设置session的过期时间
jedisClient.expire(REDIS_USER_SESSION_KEY + ":" + token, SSO_SESSION_EXPIRE);
//添加写cookie的逻辑,cookie的有效期是关闭浏览器就失效。
CookieUtils.setCookie(request, response, "TT_TOKEN", token);
//返回token
return TaotaoResult.ok(token);
}
// 根据token查询用户
@Override
public TaotaoResult getUserByToken(String token) {
//根据token从redis中查询用户信息
String json = jedisClient.get(REDIS_USER_SESSION_KEY + ":" + token);
//判断是否为空
if (StringUtils.isBlank(json)) {
return TaotaoResult.build(400, "此session已经过期,请重新登录");
}
//更新过期时间
jedisClient.expire(REDIS_USER_SESSION_KEY + ":" + token, SSO_SESSION_EXPIRE);
//返回用户信息
return TaotaoResult.ok(JsonUtils.jsonToPojo(json, TbUser.class));
}
}
UserController.java
/taotao-sso/src/main/java/com/taotao/sso/controller/UserController.java
package com.taotao.sso.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.converter.json.MappingJacksonValue;
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.utill.ExceptionUtil;
import com.taotao.common.utill.TaotaoResult;
import com.taotao.pojo.TbUser;
import com.taotao.sso.service.UserService;
/**
* 用户管理
*
* @author Lenovo
*/
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
// 数据校验接口
@RequestMapping("/check/{param}/{type}")
@ResponseBody
public Object checkData(@PathVariable String param, @PathVariable Integer type, String callback) {
TaotaoResult result = null;
// 参数有效性校验
if (StringUtils.isBlank(param)) {
result = TaotaoResult.build(400, "校验内容不能为空");
}
if (type == null) {
result = TaotaoResult.build(400, "校验内容类型不能为空");
}
if (type != 1 && type != 2 && type != 3) {
result = TaotaoResult.build(400, "校验内容类型错误");
}
// 校验出错
if (null != result) {
if (null != callback) {
MappingJacksonValue mappingJacksonValue = new MappingJacksonValue(result);
mappingJacksonValue.setJsonpFunction(callback);
return mappingJacksonValue;
} else {
return result;
}
}
// 调用服务
try {
result = userService.checkData(param, type);
} catch (Exception e) {
result = TaotaoResult.build(500, ExceptionUtil.getStackTrace(e));
}
if (null != callback) {
MappingJacksonValue mappingJacksonValue = new MappingJacksonValue(result);
mappingJacksonValue.setJsonpFunction(callback);
return mappingJacksonValue;
} else {
return result;
}
}
// 用户注册接口
@RequestMapping(value="/register", method=RequestMethod.POST)
@ResponseBody
public TaotaoResult createUser(TbUser user) {
try {
TaotaoResult result = userService.createUser(user);
return result;
} catch (Exception e) {
e.printStackTrace();
return TaotaoResult.build(500, ExceptionUtil.getStackTrace(e));
}
}
// 用户登录接口
@RequestMapping(value="/login", method=RequestMethod.POST)
@ResponseBody
public TaotaoResult userLogin(String username, String password,
HttpServletRequest request, HttpServletResponse response) {
try {
TaotaoResult result = userService.userLogin(username, password, request, response);
return result;
} catch (Exception e) {
e.printStackTrace();
return TaotaoResult.build(500, ExceptionUtil.getStackTrace(e));
}
}
// 根据token查询用户
@RequestMapping("/token/{token}")
@ResponseBody
public Object getUserByToken(@PathVariable String token, String callback) {
TaotaoResult result = null;
try {
result = userService.getUserByToken(token);
} catch (Exception e) {
e.printStackTrace();
result = TaotaoResult.build(500, ExceptionUtil.getStackTrace(e));
}
//判断是否为jsonp调用
if (StringUtils.isBlank(callback)) {
return result;
} else {
MappingJacksonValue mappingJacksonValue = new MappingJacksonValue(result);
mappingJacksonValue.setJsonpFunction(callback);
return mappingJacksonValue;
}
}
}
5.1.4 首页取cookie
http://localhost:8084/page/login
登录成功后转跳到
http://localhost:8082/
5.2 模拟拦截
需求:当访问商品详情页时强制用户登录(当有订单系统后就改为订单系统的url)
5.2.1 创建拦截器
- 需要实现handlerInterceptor接口
- 实现拦截器
- 需要在springmvc.xml中配置
LoginInterceptor.java
/taotao-portal/src/main/java/com/taotao/portal/interceptor/LoginInterceptor.java
package com.taotao.portal.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import com.taotao.common.utill.CookieUtils;
import com.taotao.pojo.TbUser;
import com.taotao.portal.service.impl.UserServiceImpl;
/**
* 使用拦截器实现用户登录
* 模拟拦截
* 创建拦截器
* @author Lenovo
*
*/
public class LoginInterceptor implements HandlerInterceptor {
@Autowired
private UserServiceImpl userService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//在Handler执行之前处理
//判断用户是否登录
//从cookie中取token
String token = CookieUtils.getCookieValue(request, "TT_TOKEN");
//根据token换取用户信息,调用sso系统的接口。
TbUser user = userService.getUserByToken(token);
//取不到用户信息
if (null == user) {
//跳转到登录页面,把用户请求的url作为参数传递给登录页面。
response.sendRedirect(userService.SSO_DOMAIN_BASE_USRL + userService.SSO_PAGE_LOGIN
+ "?redirect=" + request.getRequestURL());
//返回false
return false;
}
//取到用户信息,放行
//把用户信息放入Request
request.setAttribute("user", user);
//返回值决定handler是否执行。true:执行,false:不执行。
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// handler执行之后,返回ModelAndView之前
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// 返回ModelAndView之后。
//响应用户之后。
}
}
5.2.2 用户登录service
功能:根据token替换用户信息,需要调用sso系统的服务。返回tbuser对象。如果没有就返回null
UserService.java
/taotao-portal/src/main/java/com/taotao/portal/service/UserService.java
package com.taotao.portal.service;
import com.taotao.pojo.TbUser;
/**
* 使用拦截器实现用户登录
* 模拟拦截
* 使用拦截器实现用户登录
* @author Lenovo
*
*/
public interface UserService {
TbUser getUserByToken(String token);
}
UserServiceImpl.java
/taotao-portal/src/main/java/com/taotao/portal/service/impl/UserServiceImpl.java
package com.taotao.portal.service.impl;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.taotao.common.utill.HttpClientUtil;
import com.taotao.common.utill.TaotaoResult;
import com.taotao.pojo.TbUser;
import com.taotao.portal.service.UserService;
/**
* 用户管理Service
* 模拟拦截
* 使用拦截器实现用户登录
* @author Lenovo
*
*/
@Service
public class UserServiceImpl implements UserService {
@Value("${SSO_BASE_URL}")
public String SSO_BASE_URL;
@Value("${SSO_DOMAIN_BASE_USRL}")
public String SSO_DOMAIN_BASE_USRL;
@Value("${SSO_USER_TOKEN}")
private String SSO_USER_TOKEN;
@Value("${SSO_PAGE_LOGIN}")
public String SSO_PAGE_LOGIN;
@Override
public TbUser getUserByToken(String token) {
try {
//调用sso系统的服务,根据token取用户信息
String json = HttpClientUtil.doGet(SSO_BASE_URL + SSO_USER_TOKEN + token);
//把json转换成TaotaoREsult
TaotaoResult result = TaotaoResult.formatToPojo(json, TbUser.class);
if (result.getStatus() == 200) {
TbUser user = (TbUser) result.getData();
return user;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
resource.properties
【/taotao-portal】—【/src/main/resources/】—【resource/】—【resource.properties】
#单点登录系统的url
SSO_BASE_URL=http://127.0.0.1:8084
#根据token取用户信息url
SSO_USER_TOKEN=/user/token/
#单点登录系统登录
SSO_DOMAIN_BASE_USRL=http://sso.taotao.com
#单点登录系统登录的url
SSO_PAGE_LOGIN=/page/login/
springmvc.xml
/taotao-portal/src/main/resources/spring/springmvc.xml
<!-- 拦截器配置 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 拦截订单类请求 -->
<mvc:mapping path="/order/**" />
<bean class="com.taotao.portal.interceptor.LoginInterceptor" />
</mvc:interceptor>
</mvc:interceptors>