单点登录系统知识点总结
单点登录系统
单点登录要解决的核心问题是:一站点登录,多站点可以同时访问。
单点登录业务流程
登录页面,用户登录
判断用户名和密码是否正确
登录成功后通过uuid生成token,token相当于原来的jsessionid。
把用户信息保存到redis中,key就是token,value就是用户对象转成的json。
设置key的过期时间,模拟session的过期时间,一般为半个小时。
将token写入Cookie。Cookie要绑定二级域名,实现跨域。
将token及登录成功的结果响应给浏览器。
浏览器弹出登录成功提示框,点击确定,页面跳转到首页
在首页渲染的过程中,发送ajax请求给单点登录系统,服务端通过token获取到用户信息返回浏览器,浏览器端从返回的用户信息中获取到当前登录用户的用户名,显示到首页上。(这里会有js跨域问题,使用jsonp解决。Ajax跨域访问的时候,请求正常发过去了,服务端也把结果响应给浏览器,但是当Ajax要拿这个响应回来的数据的时候,浏览器不让拿。跨域的根在这。)
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); } |
表现层
@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;
} |
根据**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); } |
表现层
@RequestMapping(“/user/token/{token}”) @ResponseBody public e3Result getUserByToken(@PathVariable String token) { e3Result result = userService.getUserByToken(token); return result; } |
我想访问订单系统,在展示订单确认页面之前,需要对用户身份进行认证,要求用户必须登录。使用springmvc的拦截器实现。需要实现一个接口HandlerInterceptor接口。
业务流程如下:
从Cookie中取token
如果token为空,说明用户未登录,需要跳转到登录页面进行登录。在重定向到登录页面时,要将当前系统的url作为参数传过来,以便登录成功之后能再跳转到当前系统。
如果token不为空,要调用单点登录系统中的服务,根据token验证用户信息是否存在
如果不存在,说明用户登录已经过期,需要跳转到登录页面重新登录。在重定向到登录页面时,要将当前系统的url作为参数传过来,以便登录成功之后能再跳转到当前系统。
如果存在,说明用户已经登录,根据当前用户的用户id查询订单信息,将结果数据返回给浏览器。
-———————————————————————————————————————
在集群环境下,如果用Session来存放用户的登录信息,那么会出现要求用户多次登录的情况.
为解决这个问题,我们可以通过使用Session复制来解决,但是Session复制的使用会限制集群中服务器节点的数量,一旦集群中的服务器数量过多,集群的性能就会由高到低呈抛物线形式下滑。
基于此,我们想着使用一个专门的Session服务器来统一管理Session,这样一来,集群中的节点数量就没有限制了。这个专门的Session服务器就是单点登录系统.
单点登录系统使用redis模拟Session,实现Session的统一管理。
单点登录的业务流程如下:
用户在登录页面进行登录,如果登录验证不成功,返回登录页面重新登录。
登录成功后,服务端通过uuid随机生成一个名为token的字符串(相当于来的jsessionid),作为key值,并且将封装有当前登录用户信息的对象转成json字符串作为values值,以键值对的形式存入Redis缓存数据库。
设置key的过期时间,一般设为半个小时。
将token字符串写入Cookie中,返回给浏览器。在这个过程中,一般我们会同时响应一个重定向操作,让页面跳转到首页。
在页面跳转到首页以后,我们有一个要求:就是要在首页上显示出当前登录用户的用户名。这个时候,我们采取的办法是在首页加载完毕之后,向单点登录系统发送一个ajax请求,请求的参数就是Cookie。
单点登录系统接收到请求之后,取出Cookie里面存放的token字符串,去Redis中查找响应的用户信息,若查不到,会重定向到登录页面重新登录;若查到,会将用户信息由json字符串转成用户对象,并返给浏览器端。同时重设key的过期时间。
浏览器拿到返回过来的用户对象,从中取出用户名,嵌入到首页的指定位置即可。注意:在这个过程中会产生一个跨域访问的问题。
什么是跨域问题?
答:域名不同或者域名相同端口号不同均可称为跨域。首页位置前台系统中,首页通过ajax请求访问单点登录系统,两个系统彼此独立,部署在不同的Tomcat服务器上,端口号不同,是跨域请求。跨域请求能发过去,并且浏览器能得到服务端返回的用户信息,但是ajax拿不到这个响应信息,浏览器不让使用。
如何解决跨域访问问题?
答:使用jsonp技术。
至此,登录成功!
还没有评论,来说两句吧...