目录

  • 1. 单点登录系统分析
  • 1.1. 什么是SSO
  • 1.2. 原来的登录逻辑实现
  • 1.2.1. 问题
  • 1.2.2. 解决session共享问方案
  • 1.3 单点登录系统的流程
  • 2. SSO开发
  • 2.1. 系统架构
  • 2.2. 开发SSO服务
  • 2.2.1.1. 创建sso服务工程
  • 所需要的技术
  • Pom.xml
  • web.xml
  • 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. 服务开发
  • 2.3 开发注册接口
  • 2.3.1. 数据校验接口
  • 2.3.1.1 dao
  • 2.3.1.2 Service
  • UserService.java
  • UserServiceImpl.java
  • 2.3.1.3 controller
  • UserController.java
  • 2.3.1.4 测试
  • 2.3.2 用户注册接口
  • 2.3.2.1 dao
  • 2.3.2.2 Service
  • UserService.java
  • UserServiceImpl.java
  • 2.3.2.3 controller
  • UserController.java
  • 2.4 用户登录接口
  • 2.4.1 dao
  • 2.4.2 Service
  • UserService.java
  • UserServiceImpl.java
  • resource.properties
  • 2.4.3 controller
  • UserController.java
  • 2.5 根据token查询用户
  • 2.5.1业务分析
  • 2.5.2 dao层
  • 2.5.3 server层
  • UserService.java
  • UserServiceImpl.java
  • 2.5.4 controller
  • UserController.java
  • 3 用户注册
  • 3.1 静态页面
  • springmvc.xml
  • 3.2 页面跳转
  • PageController.java
  • 3.3. 需求分析
  • 4 用户登录
  • 4.1 页面跳转
  • PageController.java
  • 4.2 用户注册和用户登录的转跳
  • login.jsp
  • register.jsp
  • 4.3 需求分析
  • login.jsp
  • 4.4登录页面回调url
  • PageController.java
  • 4.5 taotao-portal项目的登录和注册
  • header.jsp
  • shortcut.jsp
  • base-v1.js
  • 5 使用拦截器实现用户登录
  • 5.1 门户系统整合sso
  • 5.1.1cookie共享:
  • 5.1.2工具类CookieUtils.java
  • CookieUtils.java
  • pom.xml
  • 5.1.3 登录接口
  • UserService.java
  • UserServiceImpl.java
  • UserController.java
  • 5.1.4 首页取cookie
  • 5.2 模拟拦截
  • 5.2.1 创建拦截器
  • LoginInterceptor.java
  • 5.2.2 用户登录service
  • UserService.java
  • UserServiceImpl.java
  • resource.properties
  • springmvc.xml


1. 单点登录系统分析

1.1. 什么是SSO

SSO英文全称Single Sign On,单点登录。SSO是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。它包括可以将这次主要的登录映射到其他应用中用于同一个用户的登录的机制。它是目前比较流行的企业业务整合的解决方案之一。

1.2. 原来的登录逻辑实现

session 共享方案 sso session共享_xml

1.2.1. 问题

单台tomcat,以上实现是没有任何问题的,但是我们现在是集群的tomcat,就会存在session共享问题。

只要解决session共享问题,登录问题即可解决。

session 共享方案 sso session共享_spring_02

每个系统都有自己的session,不能统一。

1.2.2. 解决session共享问方案

1、 tomcat的session复制

优点:不需要额外开发,只需要搭建tomcat集群即可。

缺点:tomcat 是全局session复制,集群内每个tomcat的session完全同步(也就是任何时候都完全一样的) 在大规模应用的时候,用户过多,集群内tomcat数量过多,session的全局复制会导致集群性能下降, 因此,tomcat的数量不能太多,5个以下为好。

2、 实现单点登录系统,提供服务接口。把session数据存放在redis。

Redis可以设置key的生存时间、访问速度快效率高。

优点:redis存取速度快,不会出现多个节点session复制的问题。效率高。

缺点:需要程序员开发。

session 共享方案 sso session共享_session 共享方案_03

1.3 单点登录系统的流程

session 共享方案 sso session共享_spring_04

2. SSO开发

单点登录系统是一个独立的系统,需要操作redis,连接数据库

2.1. 系统架构

session 共享方案 sso session共享_session 共享方案_05

2.2. 开发SSO服务

2.2.1.1. 创建sso服务工程

session 共享方案 sso session共享_xml_06

所需要的技术

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框架整合

session 共享方案 sso session共享_java_07

SqlMapConfig.xml

保留

db.properties

保留

resource.properties

清空内容

applicationContext-dao.xml

保留

applicationContext-jedis.xml

修改文件,并创建相关包

session 共享方案 sso session共享_xml_08

session 共享方案 sso session共享_xml_09

session 共享方案 sso session共享_session 共享方案_10

applicationContext-service.xml

修改,并创建相关包

session 共享方案 sso session共享_xml_11

applicationContext-trans.xml

session 共享方案 sso session共享_spring_12

springmvc.xml

修改,并创建相关包

session 共享方案 sso session共享_spring_13

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即可。

session 共享方案 sso session共享_java_14

2.3.1.2 Service

接受两个参数:内容、内容类型

根据内容类型查询tb_user表返回taotaoresult对象

UserService.java

/taotao-sso/src/main/java/com/taotao/sso/service/UserService.java

session 共享方案 sso session共享_java_15

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

session 共享方案 sso session共享_spring_16

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

session 共享方案 sso session共享_java_17

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 测试

session 共享方案 sso session共享_session 共享方案_18

session 共享方案 sso session共享_session 共享方案_19

session 共享方案 sso session共享_java_20

通过tb_user表查找

http://localhost:8084/check/zhangsan/1

session 共享方案 sso session共享_session 共享方案_21

http://localhost:8084/user/check/aa@a/3

session 共享方案 sso session共享_java_22

http://localhost:8084/user/check/12/4

session 共享方案 sso session共享_session 共享方案_23

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

session 共享方案 sso session共享_java_15

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

session 共享方案 sso session共享_spring_16

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

session 共享方案 sso session共享_java_17

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

session 共享方案 sso session共享_java_15

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

session 共享方案 sso session共享_spring_16

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 共享方案 sso session共享_spring_29

#用戶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

session 共享方案 sso session共享_java_17

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层

session 共享方案 sso session共享_xml_31

2.5.3 server层

接受token,调用dao到redis中查询token对应的用户信息

返回用户信息并更新过期时间

UserService.java

/taotao-sso/src/main/java/com/taotao/sso/service/UserService.java

session 共享方案 sso session共享_java_15

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

session 共享方案 sso session共享_spring_16

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

session 共享方案 sso session共享_java_17

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 静态页面

session 共享方案 sso session共享_java_35

springmvc.xml

/taotao-sso/src/main/resources/spring/springmvc.xml

session 共享方案 sso session共享_xml_36

<?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

session 共享方案 sso session共享_session 共享方案_37

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

session 共享方案 sso session共享_java_38

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

session 共享方案 sso session共享_session 共享方案_37

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

session 共享方案 sso session共享_java_40

4.2 用户注册和用户登录的转跳

login.jsp

/taotao-sso/src/main/webapp/WEB-INF/jsp/login.jsp

session 共享方案 sso session共享_xml_41

session 共享方案 sso session共享_java_42

register.jsp

/taotao-sso/src/main/webapp/WEB-INF/jsp/register.jsp

session 共享方案 sso session共享_session 共享方案_43

session 共享方案 sso session共享_session 共享方案_44

session 共享方案 sso session共享_spring_45

4.3 需求分析

login.jsp

/taotao-sso/src/main/webapp/WEB-INF/jsp/login.jsp

session 共享方案 sso session共享_xml_41

session 共享方案 sso session共享_java_47

session 共享方案 sso session共享_spring_48

4.4登录页面回调url

回调url应该是一个参数传递给显示页面的controller

参数名redirect

需要把回调的url传递给jsp页面。

当登陆成功后,js的逻辑中判断是否有回调的url,如果有就跳转到此url,如果没有就跳转到商城首页

PageController.java

/taotao-sso/src/main/java/com/taotao/sso/controller/PageController.java

session 共享方案 sso session共享_session 共享方案_37

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项目的登录和注册

session 共享方案 sso session共享_spring_50

header.jsp

/taotao-portal/src/main/webapp/WEB-INF/jsp/commons/header.jsp

session 共享方案 sso session共享_session 共享方案_51

session 共享方案 sso session共享_session 共享方案_52

shortcut.jsp

/taotao-portal/src/main/webapp/WEB-INF/jsp/commons/shortcut.jsp

session 共享方案 sso session共享_session 共享方案_53

session 共享方案 sso session共享_xml_54

base-v1.js

/taotao-portal/src/main/webapp/js/base-v1.js

session 共享方案 sso session共享_xml_55

session 共享方案 sso session共享_java_56

5 使用拦截器实现用户登录

5.1 门户系统整合sso

在门户系统中点击登录连接转跳到登录页面。登录成功后,跳转到门户系统的首页,在门户系统中需要从cookie中把taken取出来,所以必须在登录成功后把token写入cookie,并且cookie的值必须在系统之间共享

5.1.1cookie共享:
  1. domain:必须是相同的
    需要设置domain为:taotao.com
  2. 设置path为:/
    如果是localhost,不要设置domain,直接设置path即可
5.1.2工具类CookieUtils.java
CookieUtils.java

添加工具类

/taotao-common/src/main/java/com/taotao/common/utill/CookieUtils.java

session 共享方案 sso session共享_spring_57

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

添加依赖

session 共享方案 sso session共享_session 共享方案_58

<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

session 共享方案 sso session共享_java_15

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

session 共享方案 sso session共享_spring_16

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

session 共享方案 sso session共享_java_17

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/

session 共享方案 sso session共享_spring_62

5.2 模拟拦截

需求:当访问商品详情页时强制用户登录(当有订单系统后就改为订单系统的url)

5.2.1 创建拦截器
  1. 需要实现handlerInterceptor接口
  2. 实现拦截器
  3. 需要在springmvc.xml中配置
LoginInterceptor.java

/taotao-portal/src/main/java/com/taotao/portal/interceptor/LoginInterceptor.java

session 共享方案 sso session共享_xml_63

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

session 共享方案 sso session共享_spring_64

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

session 共享方案 sso session共享_xml_65

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】

session 共享方案 sso session共享_java_66

#单点登录系统的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

session 共享方案 sso session共享_spring_67

<!-- 拦截器配置 -->
	<mvc:interceptors>
		<mvc:interceptor>
			<!-- 拦截订单类请求 -->
			<mvc:mapping path="/order/**" />
			<bean class="com.taotao.portal.interceptor.LoginInterceptor" />
		</mvc:interceptor>
	</mvc:interceptors>