背景:公司内部三到四个网站项目无法合并,需要以单点登录的形式合并在一起,要求在使用时感觉就像一个项目。同时对用户信息的维护性也要得到保证,不能每次都维护所有几个项目。
思路:既然是内部网站项目,身份权限统一且几个项目同步,干脆直接在单点登录的时候随认证令牌一起分发好了。这样可以把 client 端和角色权限管理什么的直接解耦,只需要判断就可以了。用户名密码的认证和认证成功后的角色权限的取得都放在 server 端。这样如果需要维护身份信息的话,只需要维护 server 端就好了。
使用框架:CAS(网上资料最多)、shiro(支持与CAS一起实现单点登录,而且网上资料也不少)、SpringMVC
CAS的示例项目网上有很多,个人感觉找一个来用比从官网上下来自己配药方便的多。所以这里配置方法就不多说了,只说主要的地方。
CAS数据源配置:deployerConfigContext.xml中添加
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://IP地址:3306/库名" />
<property name="username" value="用户名" />
<property name="password" value="密码" />
</bean>
用户名密码认证:deployerConfigContext.xml中找到名为 “primaryAuthenticationHandler” 的 bean 。如果使用的是 AcceptUsersAuthenticationHandler 的话,干掉它,添加
<bean id="primaryAuthenticationHandler" class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler">
<property name="sql"
value="select password from 用户表名 where username=? " />
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="serviceRegistryDao" class="org.jasig.cas.services.InMemoryServiceRegistryDaoImpl"
p:registeredServices-ref="registeredServicesList" />
<util:list id="registeredServicesList">
<bean class="org.jasig.cas.services.RegexRegisteredService" p:id="0"
p:name="HTTP and IMAP" p:description="Allows HTTP(S) and IMAP(S) protocols"
p:serviceId="^(https?|imaps?)://.*" p:evaluationOrder="10000001" >
<!-- 客户端需要使用的对象的属性名称 -->
<property name="allowedAttributes">
<list>
<value>username</value>
<value>role</value>
<value>permission</value>
</list>
</property>
</bean>
</util:list>
这里的 allowedAttributes 是指注册时允许携带的属性名称
角色信息查询:
<bean id="attributeRepository"
class="com.troila.cas.MultiRowJdbcPersonAttributeDao">
<constructor-arg index="0" ref="dataSource" />
<constructor-arg index="1">
<value>
<!-- 检索SQL,根据需要自行替换 -->
<!-- SELECT * FROM APPLICATIONS WHERE -->
<!-- ID IN( SELECT APP_ID FROM -->
<!-- USER_APPS -->
<!-- WHERE USER_ID =( SELECT ID FROM USERS WHERE {0})) -->
</value>
</constructor-arg>
<!-- 检索条件字段,必须是 username -->
<property name="queryAttributeMapping">
<map>
<entry key="username" value="username" />
</map>
</property>
<!-- 名称匹配字段,指定变量名与字段名对应关系 -->
<property name="nameValueColumnMappings">
<map>
<entry key="username" value="username" />
<entry key="role" value="role" />
<entry key="permission" value="permission" />
</map>
</property>
<!-- 返回值指定 -->
<property name="resultAttributeMapping">
<map>
<!--key为对应的数据库字段名称,value为提供给客户端获取的属性名字,系统会自动填充值 -->
<entry key="username" value="usern