- 用户访问需授权的地址,Shiro拦截请求重定向到cas登录地址,附带service参数
- cas登录成功则重定向到service参数指定的地址,附加请求参数token
- Shiro拦截请求拿到token,通过http访问cas接口(2.0协议)/serviceValidate附带token和service参数,cas验证token是否有效,有效则cas重定向到service参数指定的地址,附带登录人信息
- Shiro获取到登录人信息,调用login(),登录成功
上面第3点,cas可能返回说token无效,但是这个token就是刚才cas返回的,这儿可能需要在cas端配置文件设置token的有效时长。
上面提到service参数,上面各处的参数值都是同一个,在shiro的配置文件中指定的shiro要拦截的地址
单点退出:任一客户端访问cas的登出接口,登录用户登出,cas给所有注册的客户端发送登出请求,里面附有登出的token,客户端依据这个token对服务器中的用户进行退出登录,比如根据token查找session,让session失效且清除session相关的缓存。上面提到注册的客户端,什么时候注册的呢,根据经验我猜想在客户端调用了cas的登录接口,登录成功时注册的。
第3步是在自定义的CasRealm中实现的,CasRealm继承org.apache.shiro.cas.CasRealm
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) {
CasToken casToken = (CasToken) token;
if (token == null)
return null;
String ticket = (String) casToken.getCredentials();
if (!StringUtils.hasText(ticket))
return null;
TicketValidator ticketValidator = ensureTicketValidator();
try {
Assertion casAssertion = ticketValidator.validate(ticket,
getCasService());
AttributePrincipal casPrincipal = casAssertion.getPrincipal();
Map userInfo = casPrincipal.getAttributes();
String uName = casPrincipal.getName();
log.debug("Validate ticket : {} in CAS server : {} to retrieve user : {}",
new Object[] { ticket, getCasServerUrlPrefix(), uName });
casToken.setUserId(uName);
String rememberMeAttributeName = getRememberMeAttributeName();
String rememberMeStringValue = (String) userInfo
.get(rememberMeAttributeName);
boolean isRemembered = rememberMeStringValue != null
&& Boolean.parseBoolean(rememberMeStringValue);
if (isRemembered)
casToken.setRememberMe(true);
List principals = Arrays
.asList(new Object[] {uName, userInfo });
PrincipalCollection principalCollection = new SimplePrincipalCollection(
principals, getName());
/*SecurityUtils.getSubject().getSession().setAttribute(Constants.SESSION_ATTR_USER_KEY,
user);
SecurityUtils.getSubject().getSession().setAttribute(Constants.SESSION_ATTR_SHIRO_USER_KEY,
shiroUsr);*/
return new SimpleAuthenticationInfo(principalCollection, ticket);
} catch (TicketValidationException e) {
throw new CasAuthenticationException((new StringBuilder())
.append("Unable to validate ticket [").append(ticket)
.append("]").toString(), e);
}
}