关于安全性服务,有两个重要的概念需要理解,一是认证,即判断用户是否在应用程序中存在,二是授权,即判断用户是否有权限访问资源。
Spring security为我们提供的HTTP Basic,Digest等认证服务,因为要在配置文件中对用户和权限进行配置,所以局限性很强。除此之外,它还允许我们在数据库中对用户和权限进行配置。那么如何实现呢?
在系统中定义用户,角色,权限这三种实体,一个用户可以拥有多个角色,一个角色可以被多个用户拥有,所以用户与角色之间是多对多的关系,为了易于理解,这里加入第三种实体权限,作为用户和角色的中间关联实体,把用户与角色间的多对多关系拆为两个一对多的关联关系。这样一个用户就对应着多个权限,一个权限对应着一个用户,而一个角色对应着多个权限,一个权限对应着一个角色。
一。User.java
package com.template.security; import java.util.List; /** * Created by IntelliJ IDEA. * User: Zhong Gang * Date: 11-7-28 * Time: 下午9:46 * To change this template use File | Settings | File Templates. */ public class User { private Integer id; private String username; private String password; private Boolean enabled; private List<Authority> authorities; public User() { } }
二。User.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping default-access="field"> <class name="com.template.security.User" table="user" dynamic-insert="true" dynamic-update="true"> <id name="id" column="id" type="java.lang.Integer"> <generator class="native"/> </id> <property name="username" column="username" type="java.lang.String"/> <property name="password" column="password" type="java.lang.String"/> <property name="enabled" column="enabled" type="java.lang.Boolean"/> <bag name="authorities"> <key column="userid"/> <one-to-many class="com.template.security.Authority"/> </bag> </class> </hibernate-mapping>
三。Role.java
package com.template.security;
/**
* Created by IntelliJ IDEA.
* User: Zhong Gang
* Date: 11-7-28
* Time: 下午9:47
* To change this template use File | Settings | File Templates.
*/
public class Role {
private Integer id;
private String name;
public Role() {
}
}
四。Role.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping default-access="field"> <class name="com.template.security.Role" table="role" dynamic-insert="true" dynamic-update="true"> <id name="id" column="id" type="java.lang.Integer"> <generator class="native"/> </id> <property name="name" column="name" type="java.lang.String"/> </class> </hibernate-mapping>
五。Authority.java
package com.template.security;
/**
* Created by IntelliJ IDEA.
* User: Zhong Gang
* Date: 11-7-28
* Time: 下午9:47
* To change this template use File | Settings | File Templates.
*/
public class Authority {
private Integer id;
private User user;
private Role role;
public Authority() {
}
}
六。Authority.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping default-access="field"> <class name="com.template.security.Authority" table="authority" dynamic-insert="true" dynamic-update="true"> <id name="id" column="id" type="java.lang.Integer"> <generator class="native"/> </id> <many-to-one name="user" column="userid" class="com.template.security.User"/> <many-to-one name="role" column="roleid" class="com.template.security.Role"/> </class> </hibernate-mapping>
七。security.xml
<?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd"> <beans:import resource="datasource.xml"/> <http use-expressions="true"> <intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')" requires-channel="http"/> <form-login/> <remember-me/> </http> <authentication-manager> <authentication-provider> <jdbc-user-service data-source-ref="dataSource" users-by-username-query="select username,password,enabled as status from user where username=?" authorities-by-username-query="select u.username,r.name as authority from user u join authority a on a.userid=u.id join role r on r.id=a.roleid where u.username=?"/> </authentication-provider> </authentication-manager> </beans:beans>
这里需要重点了解这样几个元素。第一个就是jdbc-user-service,这是用来配置利用数据库进行用户权限认证服务的,data-source-ref则是用来说明使用的数据库连接等相关属性,users-by-username-query则是认证用户使用的,
authorities-by-username-query则是获取用户授权的,intercept-url可以用来定义要保护的访问路径,当然如果配置文件中有多个intercept-url,其中有些是重复的,那么Spring会以位置最靠上的作为标准来判断,access则定义了哪些角色可以访问,还有其它一些属性以后再做进一步理解,现在这些已经够用了。只要做到认证和授权,那么我们的安全框架也就基本搭建完成了。
八。data.ddl
INSERT INTO user(id,username,password,enabled) VALUES (1,"ZhongGang","ZhongGang",true);
INSERT INTO user(id,username,password,enabled) VALUES (2,"GangGang","GangGang",true);
INSERT INTO user(id,username,password,enabled) VALUES (3,"ZhongZhong","ZhongGang",false);
INSERT INTO role(id,name) VALUES (1,"ROLE_ADMIN");
INSERT INTO role(id,name) VALUES (2,"ROLE_SUPERUSER");
INSERT INTO authority(id,userid,roleid) VALUES (1,1,1);
INSERT INTO authority(id,userid,roleid) VALUES (2,2,2);
INSERT INTO authority(id,userid,roleid) VALUES (3,3,1);
这是我使用的模拟数据。
当然这里需要在web.xml里面配置springSecurityFilterChain,可以参见我的另一篇博文Spring security HTTP Basic。