公司最近要求全部系统接上CAS(SSO),研究了2天,终于对接上了
闲话少叙,先了解CAS的工作原理,注:一定要了解,不然后期很难开展工作
直接上图:(注:此图别人画的,目前不晓得出处,所以对不起作者了)
开始编码:
1.导入maven依赖包
<!-- shiro cas start -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-cas</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>org.jasig.cas.client</groupId>
<artifactId>cas-client-core</artifactId>
<version>3.2.1</version>
</dependency>
<!-- shiro cas end -->
3.自定义类,并集成CasRealm
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cas.CasAuthenticationException;
import org.apache.shiro.cas.CasToken;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.CollectionUtils;
import org.apache.shiro.util.StringUtils;
import org.jasig.cas.client.authentication.AttributePrincipal;
import org.jasig.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.TicketValidationException;
import org.jasig.cas.client.validation.TicketValidator;
import org.springframework.beans.factory.annotation.Autowired;
public class CasRealm extends org.apache.shiro.cas.CasRealm{
private static final String ROLE_ID = "roleId";
private static final String PERMISSION_STRING = "permissionString";
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// 授权
String username = (String) principals.getPrimaryPrincipal();
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
Set<String> roles = null; //获取用户角色信息(调用数据库)
Set<String> permissions = null; //获取用户权限信息(调用数据库)
authorizationInfo.setRoles(roles);
authorizationInfo.setStringPermissions(permissions);
return authorizationInfo;
}
//重写CasRealm的doGetAuthenticationInfo方法,获取userId(注:userId就是username)
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
CasToken casToken = (CasToken) token;
if (token == null) {
return null;
}
String ticket = (String)casToken.getCredentials();
if (!StringUtils.hasText(ticket)) {
return null;
}
TicketValidator ticketValidator = ensureTicketValidator();
try {
Subject subject = SecurityUtils.getSubject();
// contact CAS server to validate service ticket
Assertion casAssertion = ticketValidator.validate(ticket, getCasService());
// get principal, user id and attributes
AttributePrincipal casPrincipal = casAssertion.getPrincipal();
String userId = casPrincipal.getName();
Map<String, Object> attributes = casPrincipal.getAttributes();
// refresh authentication token (user id + remember me)
casToken.setUserId(userId);
String rememberMeAttributeName = getRememberMeAttributeName();
String rememberMeStringValue = (String)attributes.get(rememberMeAttributeName);
boolean isRemembered = rememberMeStringValue != null && Boolean.parseBoolean(rememberMeStringValue);
if (isRemembered) {
casToken.setRememberMe(true);
}
// create simple authentication info
List<Object> principals = CollectionUtils.asList(userId, attributes);
PrincipalCollection principalCollection = new SimplePrincipalCollection(principals, getName());
return new SimpleAuthenticationInfo(principalCollection, ticket);
} catch (TicketValidationException e) {
throw new CasAuthenticationException("Unable to validate ticket [" + ticket + "]", e);
}
}
}
4.将类配置到spring.shiro.xml中
4.1.配置CASRealm
<!-- cas -->
<bean id="casRealm" class="你的自定义CasRealm路径">
<!-- 用切面缓存代理了 此处就不缓存了 -->
<property name="authenticationCachingEnabled" value="false"/>
<property name="authorizationCachingEnabled" value="false"/>
<!--该地址为cas server地址 -->
<property name="casServerUrlPrefix" value="${shiro.casServer.url.prefix}"/>
<!--必须和loginUrl中的service参数保持一致,否则服务器会判断service不匹配-->
<property name="casService" value="${shiro.casServer.ops.login}"/>
</bean>
4.2.使用Realm
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!-- Single realm app. If you have multiple realms, use the 'realms' property instead. -->
<property name="realm" ref="casRealm"/>
<property name="sessionManager" ref="sessionManager"/>
<property name="rememberMeManager" ref="rememberMeManager"/>
</bean>
4.3.配置Cas Filter过滤器
<!-- 配置CAS过滤器 -->
<bean id="casFilter" class="org.apache.shiro.cas.CasFilter">
<property name="failureUrl" value="${shiro.unauthorizedUrl}" />
</bean>
4.4.配置登出
<!-- 退出登录过滤器 -->
<bean id="logoutFilter" class="org.apache.shiro.web.filter.authc.LogoutFilter">
<property name="redirectUrl" value="${shiro.casServer.logout.url}${shiro.casServer.ops.main}"/>
</bean>
4.5配置shiro过滤器
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<!-- override these for application-specific URLs if you like:-->
<property name="loginUrl" value="${shiro.casServer.url.prefix}?service=${shiro.casServer.ops.login}"/>
<property name="successUrl" value="${shiro.default.success.url}" />
<property name="unauthorizedUrl" value="${shiro.unauthorizedUrl}"/>
<property name="filters">
<util:map>
<entry key="logout" value-ref="logoutFilter"/>
<entry key="cas" value-ref="casFilter" />
</util:map>
</property>
<property name="filterChainDefinitions">
<value>
/logout = logout
/login = cas
/** = user,perms,roles
</value>
</property>
</bean>