关于单点登录(Single Sign On)
概念性的东西,谷歌百度上很多资料,我这里就不详细讲了,[附上百科链接](https://baike.baidu.com/item/SSO/3451380),SSO的实现
网上也能找到一大堆资料。起初我是为了实现系统的保持登录状态,而了解到这个sso,单点登录应该会是很多系统都必须用到的一个模块,
对于每一个程序员来说,这个是必须会的技能。单点登录也有很多层次的实现,我这里就简单讲一下一个基于cookie的在同一个顶级域名下
子系统之间的sso实现原理。
关于 cookie
cookie的定义,功能我在这里不在叙述,也可以在谷歌百度上找到相关资料。在这里我主要想提到cookie的存储,维基百科上提到:按在客
户端中的存储位置,可分为内存Cookie和硬盘Cookie。内存Cookie由浏览器维护,保存在内存中,浏览器关闭后就消失了,其存在时间是短
暂的。硬盘Cookie保存在硬盘里,有一个过期时间,除非用户手工清理或到了过期时间,硬盘Cookie不会被删除,其存在时间是长期的。所以,
按存在时间,可分为非持久Cookie和持久Cookie。
在本文提到的sso实现方式中,cookie是这个实现的桥梁,是唯一的验证token。所以cookie只要拿到手,就等于有了权限,为了防止别人伪造,
这个有权限的cookie是需要加密的。而加密解密都需要在后台完成。
实现步骤
1、 用户登录,完成权限认证后,产生一个唯一的ssokey,String ssokey = des.encrypt(RANDOM.nextInt(999999) + "|" + user_id + "|" + RANDOM.nextInt(999999));
参数解析:这个user_id 可以是其他,但是最好可以跟你的当前登录用户建立起联系。这个ssokey必须是唯一的。
2、 把ssokey写入cookie,CookieUtil.set(response, domainName, cookieName, ssokey, keepLogin ? ssoCookieMaxage : -1, false);
参数解析:
domainName:共享cookie的域名,一般用顶级域名,比如我的 .huiyanxian.cn ,那么cookie在此域名底下是共享的。
cookieName:cookie的名字,可以自定义,最好跟cookie的用途相关来命名
ssokey:唯一的token,校验的证书
keepLogin:顾名思义,是否保持登录,是的话,写入cookie存在时间ssoCookieMaxage,如果不保持登录,则写入-1,cookie将在浏览器退出后删除。
false:是否加密,因为我在产生ssokey的时候已经加密过了,所以这里就不加密了 。
cookie每个人的封装习惯不一样,我只是按照我的个人封装来讲解,如果你需要封装,可以按照自己的业务,或者代码习惯来。
3、 再一次登录,或者子系统sso登录,首先查看是否有登录的session,如果没有,在看看是否有ssokey 的cookie,如果没有,跳转去sso系统登录。
登录之后,ssokey的cookie就存在了,携带ssokey请求sso服务器api,sso服务器通过这个cookie过来的ssokey,解密,拿到里面存在的user_id,
然后查询数据库取得登录的用户信息返回给子系统。 贴上子系统获取登录用户信息代码:
public static Object getLoginUser(HttpServletRequest request) {
User user = null;
try {
String ssokey = CookieUtil.get(request, cookieName);
if (StringUtils.isEmpty(ssokey)) {
ssokey = (String) request.getAttribute("ssokey");
}
user = (User) request.getSession().getAttribute("loginUser");
if (user != null) {
return user;
}
if (!StringUtils.isEmpty(ssokey)) {
String url = ssoRemoteUrl + "?ssokey=" + ssokey;
String result = HttpUtils.get(url, "UTF-8");
if (!StringUtils.isEmpty(result)) {
ObjectMapper objectMapper = new ObjectMapper();
user = objectMapper.readValue(result, User.class);
}
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return user;
}
sso服务端获取登录用户信息代码:
@RequestMapping(value = "/sso/login/getLoginUser")
public @ResponseBody Object getLoginUser(HttpServletRequest request, HttpServletResponse response, @RequestParam String ssokey) {
User user = null;
try {
if (!StringUtils.isEmpty(ssokey)) {
int user_id = getUserId(ssokey);
user = iUserService.selectById(user_id);
if (user != null) {
return user;
}
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return user;
}
sso登录完成。
总结
1、本应该附上一张流程图,无奈画图功底实在有限,就不丢出来了。本人文字表述或者实现方法可能有缺陷,还请大家指出,实现方法不止一种,这只是本人
在实现后一个小总结,如若有不正确的地方,还望大家指正,共同学习交流,如果有建议,或者想交流的同学,可以加我QQ:892662026,指出建议交流。
大家也可以使用第三方的开源sso插件,比如cas,比如kisso等等。
相关参考链接
[承一个人主页](http://www.cnblogs.com/ywlaker/p/6113927.html)
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于