说在前面的话
一、sso系统分析
什么是sso系统
SSO英文全称Single Sign On,单点登录。SSO是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。它包括可以将这次主要的登录映射到其他应用中用于同一个用户的登录的机制。它是目前比较流行的企业业务整合的解决方案之一。
传统的登录方式:
此方式在只有一个web工程时是没有问题。但是在集群环境下问题很大:
集群环境下会出现要求用户多次登录的情况。
解决方案:
1、配置tomcat集群。配置tomcatSession复制。节点数不要超过5个。(不适合)
2、可以使用Session服务器,保存Session信息,使每个节点是无状态。需要模拟Session。
3、单点登录系统是使用redis模拟Session,实现Session的统一管理。
再来看看我们的项目架构图
sso系统使用流程:
sso单点登录系统使用逻辑:
用户点击登录,若登录失败,则重新登录。若登录成功,则生成一个token存放到redis缓存中,设置过期时间,同时也存到cookies中(使用CookieUtils工具),也设置时间。然后当用户点击每一个页面时都通过ajax向服务器发送请求,请求的URL包含token的值,若在redis中找到该key,则说明没有过期,返回该key的值。若没找到,则说明登录已过期,跳转重新登录。同时设置回调页面,让用户体验好。
用户登录的service层:
@Override
public e3Result login(String username, String password) {
// 1、判断用户名密码是否正确。
TbUserExample example = new TbUserExample();
Criteria criteria = example.createCriteria();
criteria.andUsernameEqualTo(username);
//查询用户信息
List<TbUser> list = userMapper.selectByExample(example);
if (list == null || list.size() == 0) {
return e3Result.build(400, "用户名或密码错误");
}
TbUser user = list.get(0);
//校验密码
if (!user.getPassword().equals(DigestUtils.md5DigestAsHex(password.getBytes()))) {
return e3Result.build(400, "用户名或密码错误");
}
// 2、登录成功后生成token。Token相当于原来的jsessionid,字符串,可以使用uuid。
String token = UUID.randomUUID().toString();
// 3、把用户信息保存到redis。Key就是token,value就是TbUser对象转换成json。
// 4、使用String类型保存Session信息。可以使用“前缀:token”为key
user.setPassword(null);
jedisClient.set(USER_INFO + ":" + token, JsonUtils.objectToJson(user));
// 5、设置key的过期时间。模拟Session的过期时间。一般半个小时。
jedisClient.expire(USER_INFO + ":" + token, SESSION_EXPIRE);
// 6、返回e3Result包装token。
return e3Result.ok(token);
}
**redis的key是USER_INFO : token,值是password为null的user对象。
**
用户登录的controller层:
@RequestMapping(value="/user/login", method=RequestMethod.POST)
@ResponseBody
public e3Result login(String username, String password,
HttpServletRequest request, HttpServletResponse response) {
// 1、接收两个参数。
// 2、调用Service进行登录。
e3Result result = userService.login(username, password);
// 3、从返回结果中取token,写入cookie。Cookie要跨域。
String token = result.getData().toString();
CookieUtils.setCookie(request, response, COOKIE_TOKEN_KEY, token);
// 4、响应数据。Json数据。e3Result,其中包含Token。
return result;
}
cookies的key是COOKIE_TOKEN_KEY,值是token。
用户获取token是否过期的service层:
@Override
public e3Result getUserByToken(String token) {
// 2、根据token查询redis。
String json = jedisClient.get(USER_INFO + ":" + token);
if (StringUtils.isBlank(json)) {
// 3、如果查询不到数据。返回用户已经过期。
return e3Result.build(400, "用户登录已经过期,请重新登录。");
}
// 4、如果查询到数据,说明用户已经登录。
// 5、需要重置key的过期时间。
jedisClient.expire(USER_INFO + ":" + token, SESSION_EXPIRE);
// 6、把json数据转换成TbUser对象,然后使用e3Result包装并返回。
TbUser user = JsonUtils.jsonToPojo(json, TbUser.class);
return e3Result.ok(user);
}
解决ajax跨域问题
现在的的浏览器为了安全,是不让网址访问非该网址服务器,比如我在www.baidu.com上网,该网址上有请求数据去www.xiaofeng88.cn服务器上请求,然后该服务器就响应了,但是浏览器拒绝发送给baidu上。但是浏览器支持向其他网址下载js、css、jpg等文件,因此jsonp利用引入下载.js文件的原理将请求的数据带回来。当然服务器的配置也需要修改一下。
服务端:
1、接收callback参数,取回调的js的方法名。
2、业务逻辑处理。
3、响应结果,拼接一个js语句。
添加了一个参数callback,如果callback不为空,则说明前端的代码中填写了type:jsonp。
因此返回的json语句也需要修改一下。
本文讲解的很详细,希望可以给您带来灵感,如果您有问题,欢迎下方评论,博主看到后会第一时间回复大家.