天天看点

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

淘淘商城项目_11

    • 1、服务接口实现
      • 1.1、检查数据是否可用接口开发
        • 1.1.1、功能分析
        • 1.1.2、Dao
        • 1.1.3、Service
        • 1.1.4、发布服务
        • 1.1.5、引用服务
        • 1.1.6、Controller
        • 1.1.7、测试
      • 1.2、用户注册接口开发
        • 1.2.1、功能分析
        • 1.2.2、Dao
        • 1.2.3、Service
        • 1.2.4、发布服务
        • 1.2.5、引用服务
        • 1.2.6、Controller
        • 1.2.7、测试
      • 1.3、用户登录接口开发
        • 1.3.1、功能分析
        • 1.3.2、Dao
        • 1.3.3、Service
        • 1.3.4、发布服务
        • 1.3.5、引用服务
        • 1.3.6、Controller
        • 1.3.7、测试
      • 1.4、通过token查询用户信息接口开发
        • 1.4.1、功能分析
        • 1.4.2、Dao
        • 1.4.3、Service
        • 1.4.4、发布服务
        • 1.4.5、引用服务
        • 1.4.6、Controller
        • 1.4.7、测试
      • 1.5、安全退出接口开发
        • 1.5.1、功能分析
        • 1.5.2、Dao
        • 1.5.3、Service
        • 1.5.4、发布服务
        • 1.5.5、引用服务
        • 1.5.6、Controller
        • 1.5.7、测试
    • 2、实现SSO系统的登录注册功能
      • 2.1、展示登录及注册页面及首页超链接修改
      • 2.2、注册功能实现
      • 2.3、登录功能实现
    • 3、门户首页展示用户名
      • 3.1、首页展示用户名分析
      • 3.2、jsonp原理
      • 3.3、jsonp实现
        • 3.3.1、客户端:使用ajax自带的callback函数
        • 3.3.2、服务端:springmvc支持jsonp的两种实现方法

课程计划

  • 1、SSO注册功能实现
  • 2、SSO登录功能实现
  • 3、通过token获得用户信息
  • 4、ajax跨域请求解决方案–jsonp

1、服务接口实现

  

SSO系统就是解决分布式环境下登录问题的,本质上是解决分布式环境下session共享问题。

1.1、检查数据是否可用接口开发

检查数据是否可用作为注册功能的辅助。

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

1.1.1、功能分析

请求的url:/user/check/{param}/{type}

参数:从url中取参数

  1、String param(要校验的数据)

  2、Integer type(校验的数据类型)

响应的数据:json数据。TaotaoResult,封装的数据校验的结果为true:表示成功,数据可用,false:失败,数据不可用。

业务逻辑:

  1、从tb_user表中查询数据。

  2、查询条件根据传递过来的参数动态生成。

  3、判断查询结果,如果查询到数据就返回false。

  4、如果没有查询到数据就返回true。

  5、使用TaotaoResult包装,并返回。

1.1.2、Dao

  从tb_user表查询。属于单表查询,可以使用逆向工程生成的代码。

1.1.3、Service

先在taotao-sso-interface中定义接口UserRegisterService,

再在taotao-sso-service中写实现类。

参数:

  1、要校验的数据:String param

  2、数据类型:Integer type(1、2、3分别代表username、phone、email)

返回值:TaotaoResult

在taotao-sso-interface创建接口

/**
 * 用户注册管理接口
 * @author chenmingjun
 * @date 2018年12月3日 上午9:47:29
 * @version V1.0
 */
public interface UserRegisterService {
	/**
	 * 检查APP传过来的数据是否可用
	 * @param param 要校验的数据
	 * @param type 校验的数据类型
	 * @return
	 */
	TaotaoResult checkData(String param, Integer type);
}
           

在taotao-sso-service创建实现类

@Autowired
	private TbUserMapper tbUserMapper;
	
	@Override
	public TaotaoResult checkData(String param, Integer type) {
		// 1、从tb_user表中查询数据
		TbUserExample example = new TbUserExample();
		Criteria criteria = example.createCriteria();
		// 2、查询条件根据传递过来的参数动态生成
		// 1、2、3分别代表username、phone、email
		if (type == 1) {
			criteria.andUsernameEqualTo(param);
		} else if (type == 2) {
			criteria.andPhoneEqualTo(param);
		} else if (type == 3) {
			criteria.andEmailEqualTo(param);
		} else {
			return TaotaoResult.build(400, "传递过来的是非法的参数");
		}
		// 执行查询
		List<TbUser> list = tbUserMapper.selectByExample(example);
		// 3、判断查询结果,如果查询到数据就返回false
		if (list == null || list.size() == 0) {
			// 4、如果没有查询到数据就返回true
			return TaotaoResult.ok(true);
		}
		// 5、使用TaotaoResult包装,并返回
		return TaotaoResult.ok(false);
	}
           

1.1.4、发布服务

先在taotao-sso-service工程中的pom.xml文件中配置对taotao-sso-interface的依赖,因为服务层发布服务要通过该接口,

再在taotao-sso-service工程中的applicationContext-service.xml文件中发布服务:

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

1.1.5、引用服务

需要在taotao-sso-web中实现。

先在taotao-sso-web工程中的pom.xml文件中配置对taotao-sso-interface的依赖,表现层调用服务要通过该接口,

在taotao-sso-web工程中的springmvc.xml文件中引用服务:

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

1.1.6、Controller

请求的url:/user/check/{param}/{type}

参数:从url中取参数

  1、String param(要校验的数据)

  2、Integer type(校验的数据类型)

请求的方法:get。

响应的数据:json数据。TaotaoResult,封装的数据校验的结果,true:成功;false:失败。

/**
 * 用户处理Controller
 * @author chenmingjun
 * @date 2018年12月3日 上午10:31:38
 * @version V1.0
 */
@Controller
public class UserController {
	
	@Autowired
	private UserRegisterService userRegisterService;

	@RequestMapping(value="/user/check/{param}/{type}", method=RequestMethod.GET)
	@ResponseBody
	public TaotaoResult checkData(@PathVariable String param, @PathVariable Integer type) {
		TaotaoResult result = userRegisterService.checkData(param, type);
		return result;
	}
}
           

1.1.7、测试

get请求好测试,直接在浏览器中输入URL即可。

访问地址:http://localhost:8088/user/check/zhangsan/1

浏览器报404错误,原因是:我们web.xml中配置的是拦截以“.html”为后缀的请求。

我们修改访问地址:http://localhost:8088/user/check/zhangsan/1.html

此时浏览器报406错误。原因如下图:

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

而且如果我们在请求后面加上“.html”的话,等于我们修改了接口开发文档,这是不行的。

正确的做法是要拦截不带后缀的请求,我们使用“/”即拦截所有请求,如下图所示:

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

下面我们详解406错误的形成原因?

答:当我们浏览器出现406错误时,90%的原因是因为没有导入jackson-core-2.4.2.jar这个包。10%的原因是我们请求的URL后缀是“.html”。为什么呢?

原因是:在springMVC中使用注解@ResponseBody,springMVC认为对于后缀是“.html”的URL请求,服务端返回的应该也是一个html页面。但是如果服务端返回的是一个java对象的话,那么浏览器不能将一个java对象转换成一个html对象,即就会报406错误。(

这是一个大坑!

1.2、用户注册接口开发

1.2.1、功能分析

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

请求的url:/user/register

参数:表单的数据:username、password、phone、email

返回值:json数据。TaotaoResult。

接收参数:使用TbUser对象接收。

请求的方法:post

业务逻辑:

  1、使用TbUser接收提交的请求。

  2、补全TbUser其他属性。

  3、

密码要进行MD5加密

  4、把用户信息插入到数据库中。

  5、返回TaotaoResult.ok()。

1.2.2、Dao

  可以使用逆向工程生成的代码。

1.2.3、Service

在taotao-sso-interface中定义接口UserRegisterService已经定义好了,我们直接添加方法即可。

再在taotao-sso-service中写实现类,我们已经定义好了,直接实现方法即可。

参数:TbUser

返回值:TaotaoResult

在taotao-sso-interface创建接口

/**
	 * 用户注册
	 * @param tbUser 用户表
	 * @return
	 */
	TaotaoResult register(TbUser tbUser);
}
           

在taotao-sso-service创建实现类

@Override
	public TaotaoResult register(TbUser tbUser) {
		// 1、校验用户名和密码不能为空
		if (StringUtils.isEmpty(tbUser.getUsername())) {
			return TaotaoResult.build(400, "注册失败,用户名不能为空");
		}
		if (StringUtils.isEmpty(tbUser.getPassword())) {
			return TaotaoResult.build(400, "注册失败,密码不能为空");
		}
		// 2、校验数据的可用性
		// 2.1 、校验username是否可用
		TaotaoResult checkData = checkData(tbUser.getUsername(), 1);
		
		if (!(boolean) checkData.getData()) { // 说明username不可用,返回400
			return TaotaoResult.build(400, "用户名已被使用");
		}
		// 2.2、校验phone是否可用
		if (StringUtils.isNotBlank(tbUser.getPhone())) { // 说明phone不为空
			if (!(boolean) checkData.getData()) { // 说明phone不可用,返回400
				return TaotaoResult.build(400, "手机号已被使用");
			}
		}
		// 2.3、校验email是否可用
		if (StringUtils.isNotBlank(tbUser.getEmail())) { // 说明email不为空
			if (!(boolean) checkData.getData()) { // 说明email不可用,返回400
				return TaotaoResult.build(400, "邮箱已被使用");
			}
		}
		
		// 补全TbUser其他属性
		tbUser.setCreated(new Date());
		tbUser.setUpdated(tbUser.getCreated());
		// 密码的MD5加密处理
		String password = tbUser.getPassword();
		String md5Password = DigestUtils.md5DigestAsHex(password.getBytes());
		tbUser.setPassword(md5Password);
		
		// 把用户信息插入到数据库中
		tbUserMapper.insertSelective(tbUser);
		return TaotaoResult.ok();
	}
           

1.2.4、发布服务

  在taotao-sso-service工程中applicationContext-service.xml文件中发布服务,上面“1.1.4”中已经发布过了。不在赘图!

1.2.5、引用服务

  在taotao-sso-web工程中的springmvc.xml文件中引用服务,上面“1.1.5”中已经引用过了。不在赘图!

1.2.6、Controller

请求的url:/user/register

参数:表单的数据:username、password、phone、email

返回值:json数据。TaotaoResult。

接收参数:使用TbUser对象接收。

请求的方法:post

@RequestMapping(value="/user/register", method=RequestMethod.POST)
	@ResponseBody
	public TaotaoResult register(TbUser tbUser) {
		TaotaoResult result = userRegisterService.register(tbUser);
		return result;
	}
           

1.2.7、测试

post请求不好测试,需要我们新建表单,太麻烦了,我们可以使用一个工具。如下:

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

可以使用

restclient-ui-3.5-jar-with-dependencies.jar

测试接口。

点击编辑按钮,填写表单提交的content-type:application/x-www-form-urlencoded

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

点击插入参数按钮,填写参数后,点击生成。

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

点击提交按钮,测试开始。

1.3、用户登录接口开发

1.3.1、功能分析

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

请求的url:/user/login

请求的方法:POST

参数:username、password,表单提交的数据。可以使用方法的形参接收。

返回值:json数据,使用TaotaoResult包含一个token。

业务逻辑:

登录的业务流程:

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

登录的处理流程:

  1、登录页面提交用户名密码。

  2、登录成功后生成token。token相当于原来的jsessionid,字符串,可以使用uuid。

  3、把用户信息保存到redis。key就是token,value就是TbUser对象转换成的json字符串。

  4、使用String类型保存session信息。可以使用

“前缀:token”

为key。

  5、设置key的过期时间。模拟session的过期时间。一般半个小时。

  6、把token写入cookie中。

  7、cookie需要跨域。例如:www.taotao.com\sso.taotao.com\order.taotao.com,可以使用工具类。

  8、cookie的有效期。关闭浏览器失效。

  9、登录成功。

1.3.2、Dao

  查询tb_user表。单表查询。可以使用逆向工程生成的代码。

1.3.3、Service

参数:

  1、用户名:String username

  2、密码:String password

返回值:TaotaoResult,包装token。

业务逻辑:

  1、判断用户名和密码是否正确。

  2、登录成功后生成token。token相当于原来的jsessionid,字符串,可以使用uuid。

  3、把用户信息保存到redis。key就是token,value就是TbUser对象转换成的json串。

  4、使用String类型保存session信息。可以使用“前缀:token”为key。

  5、设置key的过期时间。模拟session的过期时间。一般半个小时。

  6、返回TaotaoResult包装token。

部分代码:需要设置加载属性文件。

在taotao-sso-interface创建接口

/**
 * 用户登录管理接口
 * @author chenmingjun
 * @date 2018年12月3日 下午6:04:21
 * @version V1.0
 */
public interface UserLoginService {

	/**
	 * 根据用户名和密码进行登录,生成token作为key,user作为value
	 * @param username
	 * @param password
	 * @return
	 */
	TaotaoResult login(String username, String password);
}
           

在taotao-sso-service创建实现类

@Service
public class UserLoginServiceImpl implements UserLoginService {

	@Autowired
	private TbUserMapper tbUserMapper;
	
	// 注入jedisClient对象
	@Autowired
	private JedisClient jedisClient;
	
	@Value("${USER_SESSION}")
	private String USER_SESSION;
	
	@Value("${SESSION_EXPIRE}")
	private Integer SESSION_EXPIRE;
	
	@Override
	public TaotaoResult login(String username, String password) {
		// 1、判断用户名和密码是否正确。
		TbUserExample example = new TbUserExample();
		Criteria criteria = example.createCriteria();
		criteria.andUsernameEqualTo(username);
		// 查询用户信息,校验用户名
		List<TbUser> list = tbUserMapper.selectByExample(example);
		if (list == null || list.size() == 0) { // 说明没有查询到用户信息,即用户名输入错误
			return TaotaoResult.build(400, "用户名或密码错误");
		}
		// 取出用户信息,校验密码
		TbUser tbUser = list.get(0);
		if (!DigestUtils.md5DigestAsHex(password.getBytes()).equals(tbUser.getPassword())) { // 说明密码不正确
			return TaotaoResult.build(400, "用户名或密码错误");
		}
		
		// 2、登录成功后生成token。token相当于原来的jsessionid,字符串,可以使用uuid。
		String token = UUID.randomUUID().toString();
		// 我们密码就不要存到redis中了,所以要清空密码
		tbUser.setPassword(null);
		// 3、把用户信息保存到redis。key就是token,value就是TbUser对象转换成的json串。
		// 4、使用String类型保存session信息。可以使用“前缀:token”为key。
		jedisClient.set(USER_SESSION + ":" + token, JsonUtils.objectToJson(tbUser));
		// 5、设置key的过期时间。模拟session的过期时间。一般半个小时。
		jedisClient.expire(USER_SESSION + ":" + token, SESSION_EXPIRE);
		
		// 6、返回TaotaoResult包装token。
		return TaotaoResult.ok(token);
	}
}
           

1.3.4、发布服务

在taotao-sso-service工程中applicationContext-service.xml文件中发布服务:

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

在taotao-sso-service工程中applicationContext-dao.xml文件中加载配置文件:

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

配置文件内容如下:

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

1.3.5、引用服务

在taotao-sso-web工程中的springmvc.xml文件中引用服务:

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

1.3.6、Controller

请求的url:/user/login

请求的方法:POST

参数:username、password,表单提交的数据。

因为只有两个参数,所以不用使用pojo来接收,可以使用方法的形参接收就可以。

从返回结果中取出token,写入cookie。需要使用HttpServletRequest、HttpServletResponse

返回值:json数据,使用TaotaoResult包含一个token。

业务逻辑:

  1、接收表单提交的两个参数。

  2、调用Service层的方法进行登录。

  3、从返回结果中取token,写入cookie。注意:cookie要跨域。

   

cookie的二级域名跨域需要进行设置

   1)setDomain(),设置一级域名:

    .itcast.cn

    .taotao.com

    .taotao.com.cn

   2)setPath(),设置为“/”

   可以使用工具类。工具类放到taotao-common工程中。

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

   需要加入servlet-api的依赖包:在common项目中的pom.xml中,加入依赖:

<dependency>
    	<groupId>javax.servlet</groupId>
    	<artifactId>servlet-api</artifactId>
    	<scope>provided</scope>
    </dependency>
           

注意:

scope

的值是

provided

,表示

该jar包在运行时使用

编译时使用

测试时用

,但是

打包的时候不用

,因为该jar包web容器tomcat会提供,如果打包的时候使用该jar包,会

出现冲突

  4、响应数据。json数据。TaotaoResult,其中包含token。

@RequestMapping(value="/user/login", method=RequestMethod.POST)
	@ResponseBody
	public TaotaoResult login(String username, String password, HttpServletRequest request, HttpServletResponse response) {
		// 1、接收表单提交的两个参数。
		// 2、调用Service层的方法进行登录。
		TaotaoResult result = userLoginService.login(username, password);
		// 3、从返回结果中取出token,写入cookie。注意:cookie要跨域。
		if (result.getStatus() == 200) {
			String token = result.getData().toString(); // 从返回结果中取出token
			CookieUtils.setCookie(request, response, COOKIE_TOKEN_KEY, token);
		}
		return result;
	}
           

在taotao-sso-web工程中springmvc.xml文件中加载配置文件:

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

配置文件内容如下:

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

1.3.7、测试

使用

restclient-ui-3.5-jar-with-dependencies.jar

测试接口,查看Body;然后查看redis服务器中的key。

1.4、通过token查询用户信息接口开发

1.4.1、功能分析

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

请求的url:/user/token/{token}

参数:String token(需要从url中取)

返回值:json数据。使用TaotaoResult包装Tbuser对象。

业务逻辑:

  1、从url中取参数。

  2、根据token查询redis。

  3、如果查询不到数据,则返回用户已经过期。

  4、如果查询到数据,则说明用户已经登录。

  5、需要重置key的过期时间。

  6、把json数据转换成TbUser对象,然后使用TaotaoResult包装并返回。

1.4.2、Dao

  使用JedisClient对象进行查询。

1.4.3、Service

参数:String token

返回值:TaotaoResult

在taotao-sso-interface创建接口

/**
	 * 根据token从redis中查询用户信息
	 * @param token
	 * @return
	 */
	TaotaoResult getUserByToken(String token);
           

在taotao-sso-service创建实现类

@Override
	public TaotaoResult getUserByToken(String token) {
		// 2、根据token查询redis。
		String jsonString = jedisClient.get(USER_SESSION + ":" + token);
		if (StringUtils.isBlank(jsonString)) {
			// 3、如果查询不到数据,则返回用户已经过期。
			return TaotaoResult.build(400, "用户登录状态已过期,请重新登录");
		}
		// 4、如果查询到数据,则说明用户已经登录。
		// 5、需要重置key(USER_SESSION)的过期时间。
		jedisClient.expire(USER_SESSION + ":" + token, SESSION_EXPIRE);
		// 6、把json数据转换成TbUser对象,然后使用TaotaoResult包装并返回。
		TbUser tbUser = JsonUtils.jsonToPojo(jsonString, TbUser.class);
		return TaotaoResult.ok(tbUser);
		// return TaotaoResult.ok(json);
	}
           

注意:如果返回的是:return TaotaoResult.ok(json);

那么返回的json串中会有转义字符,如下:

{
"status": 200
"msg": "OK"
"data": "{\"id\":1,\"username\":\"zhangsan\",\"password\":null,\"phone\":\"15800807944\",\"email\":\"[email protected]\",\"created\":1414119176000,\"updated\":1414119179000}"
}
           

这跟我们接口开发文档中的格式不一样,接口开发文档中的格式如下:

{
"status": 200
"msg": "OK"
"data": {"id":1,"username":"zhangzhijun","password":null,"phone":"15800807944","email":"[email protected]","created":1414119176000,"updated":1414119179000}
}
           

1.4.4、发布服务

  在taotao-sso-service工程中applicationContext-service.xml文件中发布服务,上面“1.3.4”中已经发布过了。不在赘图!

1.4.5、引用服务

  在taotao-sso-web工程中的springmvc.xml文件中引用服务,上面“1.3.5”中已经引用过了。不在赘图!

1.4.6、Controller

请求的url:/user/token/{token}

参数:String token (需要从url中取)

返回值:json数据。使用TaotaoResult包装Tbuser对象。

@RequestMapping(value="/user/token/{token}", method=RequestMethod.GET)
	@ResponseBody
	public TaotaoResult getUserByToken(@PathVariable String token) {
		TaotaoResult result = userLoginService.getUserByToken(token);
		return result;
	}
           

1.4.7、测试

get请求好测试,直接在浏览器中输入URL即可。

访问地址:http://localhost:8088/user/token/cd3c4925-c780-4e15-b8c2-ca9dc764fe47

1.5、安全退出接口开发

1.5.1、功能分析

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

需要根据token删除redis中对应的key。

从接口文档可知

url:user/logout/{token}

参数:token

返回值:由TaotaoResule封装的信息"ok"。

1.5.2、Dao

  直接使用RedisClient访问redis。

1.5.3、Service

在taotao-sso-interface创建接口

/**
	 * 根据token从redis删除对应的key
	 * @param token
	 * @return
	 */
	TaotaoResult logout(String token);
           

在taotao-sso-service创建实现类

@Override
	public TaotaoResult logout(String token) {
		jedisClient.expire(USER_SESSION + ":" + token, 0);
		return TaotaoResult.ok();
	}
           

1.5.4、发布服务

  在taotao-sso-service工程中applicationContext-service.xml文件中发布服务,上面“1.3.4”中已经发布过了。不在赘图!

1.5.5、引用服务

  在taotao-sso-web工程中的springmvc.xml文件中引用服务,上面“1.3.5”中已经引用过了。不在赘图!

1.5.6、Controller

url:user/logout/{token}

参数:token

@RequestMapping(value="/user/logout/{token}", method=RequestMethod.GET)
	@ResponseBody
	public TaotaoResult logout(@PathVariable String token) {
		TaotaoResult result = userLoginService.logout(token);
		return result;
	}
           

1.5.7、测试

安装taotao-sso,启动taotao-sso、taotao-sso-web。

从redis中找一个存在的token:70ae13a6-87bb-4e3a-b713-35d7979c4bd8

使用RESETClirnt测试访问,删除token:70ae13a6-87bb-4e3a-b713-35d7979c4bd8 的用户

提示删除成功!

2、实现SSO系统的登录注册功能

2.1、展示登录及注册页面及首页超链接修改

第一步:加入静态文件及JSP页面

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

第二步:在taotao-sso-web的springmvc.xml文件中配置资源映射标签,即不拦截静态资源。

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

第三步:点击门户首页登录按钮,浏览器URL为:

  http://localhost:8084/page/login,报错:

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

第四步:点击门户首页的免费注册按钮,浏览器的URL为:

  http://localhost:8084/page/register,报错:

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

由此我们发现,其实登录注册的URL非常类似:

  http://localhost:8084/page/register

  http://localhost:8084/page/login

所以通过

/page/{page}

的方式请求,通过

URL模板映射

,使用

@PathVariable注解

即可接收请求,转发jsp页面,代码如下:

使用rsetful,跳转不同页面

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

第五步:修改端口号为访问登录注册的端口号为

8088

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

测试:通过。

2.2、注册功能实现

/taotao-sso-web/src/main/webapp/WEB-INF/jsp/register.jsp分析:

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

提交之前检查:

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

注册,提交表单:

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

分析得出,此时的登录功能应该是可以使用了。

2.3、登录功能实现

/taotao-sso-web/src/main/webapp/WEB-INF/jsp/login.jsp分析:

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

文档加载时,调用方法,一旦点击,则提交表单:

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

表单提交:

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

分析得出,登录功能也是可以使用的。

3、门户首页展示用户名

3.1、首页展示用户名分析

1、在taotao-sso-web工程中,当用户登录成功后,在cookie中有token信息。

2、在taotao-portal-web工程中,从cookie中取出token,携带token发送格式为jsonp的请求,根据token从taotao-sso-web工程中查询用户信息。

3、把从taotao-sso-web工程中查询到的用户名展示到首页taotao-portal-web工程中。

方案一:在Controller中取cookie中的token数据,调用sso服务查询用户信息。

  缺点:由于淘淘商城首页footer.jsp,在每个系统中都有,可以在每一个系统的footer.jsp中写一个ajax发起请求调用当前系统的Controller,设置模型数据,然后展示数据。麻烦!

方案二:当页面加载完成后使用js取cookie中token的数据,使用ajax请求查询用户信息的JSON数据。只需要在页面实现一次即可。

乍一看方案一与方案二是一样的,其实不是,方案一需要在每一个系统都编写Controller,方案二只需要在taotao-sso-web编写一个Controller即可。而且方案一是立即可行的,但是方案二的服务接口在sso系统中。sso.taotao.com(localhost:8088),在首页显示用户名称,首页的域名是www.taotao.com(localhost:8082),使用ajax请求跨域了。

什么是跨域:

  1、域名不同。

  2、域名相同端口不同。

例如:
    www.taotao.com --> 请求 www.taobao.com  也是跨域
    www.taotao.com --> 请求 sso.taotao.com  也是跨域
    www.taotao.com:8080 --> www.taotao.com:8088  也是跨域
    localhost:8080 --> localhost:8088  也是跨域
    www.taotao.com --> www.taotao.com  不是跨域
           

只有域名和端口完全一样才不是跨域。

js不可以跨域请求JSON数据

解决js的跨域问题可以使用jsonp。

jsonp

不是新技术

是跨域的解决方案

。使用js的特性绕过跨域请求,特性:

js可以跨域加载js文件

3.2、jsonp原理

举个非常常见的例子,我们在html头部一般都会引入很多js,甚至我们直接引用在线的js,比如我们引用官方网站的jQuery路径加载进来也是可以的。jQuery的官方域名与我们的工程所在的域名肯定是不一样的,但是不影响使用,这就是我们所说的js可以跨域请求js文件!

即:ajax无法跨域请求别的url,我们可以使用ajax跨域加载js文件。

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

http://localhost:8088/user/token/4ffd07a2-1f92-4601-94ff-2ab763931018?callback=fun

8088做处理:查询到JSON数据,拼接成fun({“id”:1});

8082浏览器加载fun({“id”:1});

调用fun方法,里面参数就是JSON数据。做相关的处理。

更加详细的解释:

参考链接:https://blog.csdn.net/pdsu161530247/article/details/82189866

3.3、jsonp实现

3.3.1、客户端:使用ajax自带的callback函数

使用jQuery。

在/taotao-portal-web/src/main/webapp/js/taotao.js中:

使用ajax的dataType : “jsonp”,将success : function当做回调函数。

客户端是taotao-portal-web工程:

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

taotao.js代码如下:

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

3.3.2、服务端:springmvc支持jsonp的两种实现方法

ajax设置的callback函数,我们在后端就需要封装一个callback(jsondata),让前端将jsondata作为参数调用。

方法一:springmvc4.1之前的实现方法

服务端是taotao-sso-web工程:

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

方法二:springmvc4.1之后的实现方法

springmvc4.1以后,下面两行代码会自动帮我们封装callback(jsondata)

服务端是taotao-sso-web工程:

day78_淘淘商城项目_11_实现SSO系统的登录注册功能 + 门户首页展示用户名 + ajax请求跨域问题详解_匠心笔记

我的GitHub地址:https://github.com/heizemingjun

我的博客园地址:https://www.cnblogs.com/chenmingjun

我的蚂蚁笔记博客地址:https://blog.leanote.com/chenmingjun

Copyright ©2018~2019 黑泽君

【转载文章务必保留出处和署名,谢谢!】