8、单点登录原理
前言
主要是看图,其实很详细的
相同域名下实现单点登录太简单,因为A系统和B系统域名相同,在访问A时候登录过,在访问B时,由于域名相同,浏览器会带上cookies,cookies里有票据信息,访问B自然就不用再登录了。
可是如果A系统和B系统域名不同,CAS是怎样做到已经在访问A系统时候登录过,在访问B系统时就不用再重新登录了呢?此时访问B系统,因为域名不同的缘故,浏览器没有带上存储有票据信息的cookies啊,好了此时CAS实现单点登录的原理是这样的,请看图:
下面二者具体看代码
• TGT(Ticket Grangting Ticket)
TGT是CAS为用户签发的登录票据,拥有了TGT,用户就可以证明自己在CAS成功登录过。TGT封装了Cookie值以及此Cookie值对应的用户信息。
用户在CAS认证成功后,CAS生成cookie(叫TGC),写入浏览器,同时生成一个TGT对象,放入自己的缓存,TGT对象的ID就是cookie的值。
当HTTP再次请求到来时,如果传过来的有CAS生成的cookie,则CAS以此cookie值为key查询缓存中有无TGT ,如果有的话,则说明用户之前登录过,如果没有,则用户需要重新登录。
• ST(Service Ticket)
ST是CAS为用户签发的访问某一service的票据。用户访问service时,service发现用户没有ST,则要求用户去CAS获取ST。用户向CAS发出获取ST的请求,如果用户的请求中包含cookie,则CAS会以此cookie值为key查询缓存中有无TGT,如果存在TGT,则用此TGT签发一个ST,返回给用户。用户凭借ST去访问service,service拿ST去CAS验证,验证通过后,允许用户访问资源。
1)用户访问cas-client,被拦截跳转到cas-server进行登录,输入正确的用户信息
2)登录成功后,cas-server签发一个TGC票据,写入浏览器同时生成一个TGT对象,放入自己的缓存,TGT对象的ID就是cookie的值,并再次跳转到cas-client,同时携带着ST票据
cas-client发现有ST票据则拿着ST票据去cas-server验证,如果验证通过,则返回用户名信息
3)cas-client登录成功,用户访问另一个cas-client2时,也会被拦截再次跳转到cas-server发现TGC票据生成的TGT对象的ID值存在则直接验证通过,签发一个ST票据给cas-client2。
TGT cookie 存储在关于服务器域名的cookie
1、问:系统A是如何发现该请求需要登录重定向到认证中心的?
答:用户通过浏览器地址栏访问系统A,系统A(也可以称为CAS客户端)去Cookie中拿JSESSION,即在Cookie中维护的当前回话session的id,如果拿到了,说明用户已经登录,如果未拿到,说明用户未登录。
2、问:系统A重定向到认证中心,发送了什么信息或者地址变成了什么?
答:假如系统A的地址为http://a:8080/,CAS认证中心的服务地址为http://cas.server:8080/,那么重点向前后地址变化为:http://a:8080/————>ttp://cas.server:8080/?service=http://a:8080/,由此可知,重点向到认证中心,认证中心拿到了当前访问客户端的地址。
3、问:登录成功后,认证中心重定向请求到系统A,认证通过令牌是如何附加发送给系统A的?
答:重定向之后的地址栏变成:http://a:8080/?ticket=ST-XXXX-XXX,将票据以ticket为参数名的方式通过地址栏发送给系统A
4、问:系统A验证令牌,怎样操作证明用户登录的?
答:系统A通过地址栏获取ticket的参数值ST票据,然后从后台将ST发送给CAS server认证中心验证,验证ST有效后,CAS server返回当前用户登录的相关信息,系统A接收到返回的用户信息,并为该用户创建session会话,会话id由cookie维护,来证明其已登录。
5、问:登录B系统,认证中心是如何判断用户已经登录的?
答:在系统A登录成功后,用户和认证中心之间建立起了全局会话,这个全局会话就是TGT(Ticket Granting Ticket),TGT位于CAS服务器端,TGT并没有放在Session中,也就是说,CAS全局会话的实现并没有直接使用Session机制,而是利用了Cookie自己实现的,这个Cookie叫做TGC(Ticket Granting Cookie),它存放了TGT的id,保存在用户浏览器上。
用户发送登录系统B的请求,首先会去Cookie中拿JSESSION,因为系统B并未登录过,session会话还未创建,JSESSION的值是拿不到的,然后将请求重定向到CAS认证中心,CAS认证中心先去用户浏览器中拿TGC的值(用户已经登录过),也就是全局会话id,如果存在则代表用户在认证中心已经登录,附带上认证令牌重定向到系统B。
上面登录状态判断也是这个逻辑。
6、问:登出的过程,各个系统对当前用户都做了什么
答:认证中心清除当前用户的全局会话TGT,同时清掉cookie中TGT的id:TGC;
然后是各个客户端系统,比如系统A、系统B,清除局部会话session,同时清掉cookie中session会话id:jsession
1、基本概念 、cookie, session, 会话cookie, jssessionid
- cookie 和 session机制都是为了解决HTTP协议的无状态性而生的
- cookie 是客户端保存用户信息的机制
- session 是服务器端保存用户信息的机制
- cookie其实就是保存在浏览器中的一小段文本,当浏览器第一次访问jsp时,jsp response会给浏览器生成一个cookie,然后浏览器会存储它
- cookie 具有不可跨域性
- cookie 和session 联合使用可以解决跨域记录用户信息的问题
- 为了使浏览器记住服务器上的session,浏览器会生成一个id , 这个id就叫做jsessionid
另外,由于一些浏览器禁用cookie, Java EE标准 退出了URL重写,使url里面记录jssessionid、单点的概率的jsessionid是存在单点登录服务器端的
上述让浏览器记住服务器上的session的形式就叫做会话cookie,会话cookie在用户登出或者浏览器关闭后自动删除,这样就叫做一次会话。
理解了上面的基本概念和标准,对于理解cas的实现和基本流程很有帮助,cas这样的sso解决方案本来就是构建在cookie和session标准之上的。
1.1、从cookie中获取jssensionid
Cookie[] cookies = request.getCookies();
for(Cookie cookie:cookies){
if(cookie.getName().equals("JSESSIONID")){
log.info("cookie:"+cookie.getName()+"value:"+cookie.getValue());
loginResultData.setJSESSIONID(cookie.getValue());
}
}
cookieName:JSESSIONID-value:E5E7A0895E652C49CE066220680E243E
1.2.1、获取session
根据结果很明显我们可以看session中存放的是单点登录携带的信息
//获取session
HttpSession session = request.getSession();
// 获取session中所有的键值
Enumeration<String> attrs = session.getAttributeNames();
// 遍历attrs中的
while(attrs.hasMoreElements()){
// 获取session键值
String name = attrs.nextElement().toString();
// 根据键值取session中的值
Object vakue = session.getAttribute(name);
// 打印结果
System.out.println("------" + name + ":" + vakue +"--------\n");
}
sessionName::_const_cas_assertion_-value:org.jasig.cas.client.validation.AssertionImpl@12d08532
1.2.2、从session中获取信息
Assertion assertion = session != null ? (Assertion) session.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION):null;
// 判断是否登录过,如果已经登录过,进入if并且退出
if (assertion != null){
log.info("session中获取的"+assertion.getPrincipal().toString());
}
session中获取的test@test.com
2、客户端验证是否登录
)
@ResponseBody
@GetMapping(value = "healerjean/validate",produces="application/json;charset=utf-8" )
public ResponseBean invalidate(HttpServletRequest request){
Cookie[] cookies = request.getCookies();
String JSESSIONID = null;
String loginSessionId = null ;
for(Cookie cookie:cookies){
if(cookie.getName().equals("JSESSIONID")){
JSESSIONID = cookie.getValue();
}
if(cookie.getName().equals("loginSessionId")){
loginSessionId = cookie.getValue();
}
}
LoginResultData loginResultData = new LoginResultData() ;
if(StringUtils.isNotBlank(JSESSIONID)&&StringUtils.isNotBlank(loginSessionId)&&StringUtils.equals(JSESSIONID,loginSessionId )){
loginResultData.setJSESSIONID(JSESSIONID);
return ResponseBean.buildSuccess(loginResultData);
}
return ResponseBean.buildFailure("401","未认证,请重新登录");
}
@Value("${server.login.redirect.url}")
private String server_login_redirect_url;
/**
* 首页面进入之后,跳转到前端url界面,如果是前后端分离用的两个域名的情况下
* @return
*/
@GetMapping(value = {"/",""} )
public String loginDev(HttpServletRequest request,HttpServletResponse response){
Cookie cookieLogin = new Cookie("loginSessionId", getJsessionId(request));
cookieLogin.setComment("存储客户端登录状态,防止服务器重启之后,session自动刷新"); // Cookie描述
cookieLogin.setMaxAge(24*60*60); // Cookie有效时间 24小时
response.addCookie(cookieLogin); //给客户端添加cookie
return "redirect://"+server_login_redirect_url;
}
public String getJsessionId(HttpServletRequest request){
Cookie[] cookies = request.getCookies();
for(Cookie cookie:cookies){
if(cookie.getName().equals("JSESSIONID")){
return cookie.getValue();
}
}
return null ;
}
如果满意,请打赏博主任意金额,感兴趣的请下方留言吧。可与博主自由讨论哦
支付包 | 微信 | 微信公众号 |
---|---|---|
![]() |
![]() |
![]() |