目录
1.需求:
在分布式应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统,登录成功后显示用户信息。
2.分析
传统的登录实现方式,在只有一个web项目时是没有问题的。
集群环境下会出现要求用户多次登录的情况。
解决方案:
1.配置tomcat集群。配置tomcatSession复制。节点数不要超过5个。
2.使用单点登录系统,通过redis模拟Session,实现Session的统一管理。
3.思路
- sso注册功能
- sso登录功能
- 用户登录成功后(服务层)使用UUID随机生成一串字符串用来模拟session,命名为token。将token set进Redis,key: "SESSION:"+token value: json字符串形式的user信息,设置session过期时间(半小时),返回token
- 用户登录成功后(表现层)调用登录服务获取token,将token写入cookie。key: "token" value: token,返回token
- 用户登录成功后显示用户信息思路
- 表现层登录成功后将用户信息传递给页面(每个需要展示用户信息的页面都要写一个controller,不可取)
- 前端js查询cookie中的token作为参数,使用ajax向后台发送请求获取用户信息(jsonp跨域——推荐)
4.代码实现
用户表DDL
CREATE TABLE `tb_user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL COMMENT '用户名',
`password` varchar(32) NOT NULL COMMENT '密码,加密存储',
`phone` varchar(20) DEFAULT NULL COMMENT '注册手机号',
`email` varchar(50) DEFAULT NULL COMMENT '注册邮箱',
`created` datetime NOT NULL,
`updated` datetime NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`) USING BTREE,
UNIQUE KEY `phone` (`phone`) USING BTREE,
UNIQUE KEY `email` (`email`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 COMMENT='用户表';
注册服务层
package lx.test.sso.service.impl;
import java.util.Date;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import lx.test.mapper.TbUserMapper;
import lx.test.pojo.TbUser;
import lx.test.pojo.TbUserExample;
import lx.test.pojo.TbUserExample.Criteria;
import lx.test.sso.service.RegisterService;
import lx.test.utils.E3Result;
/**
* 用户注册service
* @author lx
*
*/
@Service
public class RegisterServiceImpl implements RegisterService {
@Autowired
private TbUserMapper userMapper;
@Override
public E3Result checkData(String param, int type) {
TbUserExample example = new TbUserExample();
Criteria criteria = example.createCriteria();
if (type == 1) {
criteria.andUsernameEqualTo(param);
} else if (type == 2) {
criteria.andPhoneEqualTo(param);
} else if (type == 3) {
criteria.andEmailEqualTo(param);
} else {
return E3Result.build(400, "非法的参数");
}
List<TbUser> list = userMapper.selectByExample(example);
if(list == null||list.size() == 0){
return E3Result.ok(true);
}
return E3Result.ok(false);
}
@Override
public E3Result register(TbUser user) {
if (StringUtils.isBlank(user.getUsername())) {
return E3Result.build(400, "用户名不能为空");
}
if (StringUtils.isBlank(user.getPassword())) {
return E3Result.build(400, "密码不能为空");
}
if (StringUtils.isBlank(user.getPhone())) {
return E3Result.build(400, "手机号不能为空");
}
//数据有效性校验1.用户名2.手机号
E3Result result = checkData(user.getUsername(), 1);
if(!(boolean) result.getData()){
return E3Result.build(400, "此用户名已经被使用");
}
result = checkData(user.getPhone(), 2);
if(!(boolean) result.getData()){
return E3Result.build(400, "此手机号已经被使用");
}
user.setCreated(new Date());
user.setUpdated(new Date());
String md5pass = DigestUtils.md5DigestAsHex(user.getPassword().getBytes());
user.setPassword(md5pass);
userMapper.insert(user);
return E3Result.ok();
}
}
注册表现层
package lx.test.sso.controller;
import org.springframework.beans.factory.annotation.Autowired;
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 lx.test.pojo.TbUser;
import lx.test.sso.service.RegisterService;
import lx.test.utils.E3Result;
/**
* 商品注册controller
* @author lx
*
*/
@Controller
public class RegisterController {
@Autowired
private RegisterService registerService;
@RequestMapping("/page/register")
public String showRegister(){
return "register";
}
@RequestMapping("/user/check/{param}/{type}")
@ResponseBody
public E3Result checkData(@PathVariable String param,@PathVariable int type) {
E3Result result = registerService.checkData(param, type);
return result;
}
@RequestMapping(value="/user/register",method=RequestMethod.POST)
@ResponseBody
public E3Result register(TbUser user) {
E3Result result = registerService.register(user);
return result;
}
}
register.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page trimDirectiveWhitespaces="true" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="Cache-Control" content="no-cache,must-revalidate">
<title>注册-个人用户</title>
<link rel="stylesheet" type="text/css" href="/css/headerfooter.css" />
<link rel="stylesheet" type="text/css" href="/css/jquery.alerts.css" />
<link rel="stylesheet" type="text/css" href="/css/headerfooterindex.css" />
<script type="text/javascript" src="/js/jquery-1.5.1.min.js"></script>
<script type="text/javascript" src="/js/jquery.cookie.js"></script>
<script type="text/javascript" src="/js/passport.common.js?v20140531"></script>
<script type="text/javascript" src="/js/jquery.alerts.js"></script>
<script type="text/javascript" src="/js/png.js?v20140521"></script>
</head>
<body>
<!-- header -->
<div class="header">
<a href="http://www.e3mall.cn"><img src="/images/logo.png" border="0" /><span>欢迎注册</span></a>
</div>
<!--mainStart-->
<link rel="stylesheet" type="text/css" href="/css/reg.css?v20140432" />
<script type="text/javascript" src="/js/allMail.js?v20140430"></script>
<script type="text/javascript