安全域是Tomcat服务器用来保护web应用资源的一种机制.在安全域中可以配置安全验证信息,即用户信息(包括用户名和密码)以及用户角色的映射关系.每个用户可以拥有一个或多个角色,每个角色限定了可访问的资源.一个用户可以访问其拥有的所有角色的资源.客户必须以某种用户身份才能登录到应用系统,该客户只能访问与这种身份对应的资源.
客户,用户,角色,资源的关系如下图:
如上图所示,如果客户以用户一的身份登录,则他有角色一和角色二两个角色,而角色一可以访问资源一和资源三;角色二可以访问资源二.所以用户一可以访问资源一,二和三.
安全域是Tomcat内置的功能,在org.apache.catalina.Realm接口中声明了把一组用户名,口令及所关联的角色集成到tomcat 的方法.tomcat5提供四种实现这一接口的类,分别代表四种安全域:
内存域 | MemoryRealm | 在初始化阶段.从XML文件中读取安全验证信息,并把它们以一组对象的形式存放在内存中 |
JDBC域 | JDBCRealm | 通过JDBC驱动程序访问存放在数据库中的安全验证信息 |
数据源域 | DataSourceRealm | 通过JNDI数据源访问存放在数据库中的安全验证信息 |
JNDI域 | JNDIRealm | 通过JNDIprovider访问存放在基于LDAP的目录服务器中的安全验证信息 |
不管配置哪能一种类型的安全域,都有如下步骤:
1.为web资源设置安全约束.
2.在conf/server.xml中配置<Realm>元素.在元素中指定相关属性.形式如下:
<Realm className=””../>
Realm元素可以嵌套在三种容器元素中,这直接决定了realm的作用范围.
嵌到<Engin>中 | 所有虚拟主机上的所有应用共享,除非Engin下的Host或Context还定义了自己的Realm |
嵌到<Host>中 | Host下所有的应用共享.除非在Host下的Context还定义了各自的. |
嵌到<Context>中 | 只有Context元素中的web应用才能使用这个元素. |
设置安全约束
有一网上商店,假定它包含三个入口:/shop;/admin;/order.其中,用户只能访问/shop;管理员可以访问/admin;销售人员可以进入/order;
小张是销售人员,所以他可以进入/order;但他也可以买东西,所以他也是用户,可以进入/shop
为web资源设定安全约束时,只指定某种资源可以被哪些角色访问,并不涉及用户信息.用户信息以及角色的映射关系是在配置<Realm/>元素时设定的.
为资源设定约束需要在web应用的web.xml文件中加入<security-constranint>,<login-config>和<security-role>元素.
security-constranint
该元素声明可以访问资源的角色以及访问的方式,如;get,post,head,delete等;如:
< security-constraint>
<display-name>TestSecurity</display-name>
<web-resource-collection>
<web-resource-name>Protected</web-resource-name>
<url-pattern>*.jsp</url-pattern>
<url-pattern>*.do</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</ security-constraint>
上面的声明提出:只有admin这个角色才能访问应用中的*.jsp,*.do 资源.
另一实例:
< security-constraint>
<display-name>TestSecurity</display-name>
<web-resource-collection>
<web-resource-name>Protected</web-resource-name>
<url-pattern>/protected/*</url-pattern>
<http-method>GET</http-method >
<http-method>POST</http-method >
</web-resource-collection>
<auth-constraint>
<role-name>tomcat</role-name>
<role-name>role1</role-name>
</auth-constraint>
</ security-constraint>
上面声明指出:只有tomcat和role1 两个角色可以以Get,Post访问/protectd/*下的资源.
security-constranint的属性有:
<web-resource-collection> | 声明受保护的资源 |
<web-resource-name> | 标识受保护的web资源 |
<url-pattern> | 指定受保护的路径 |
<http-method> | 指定受保护的HTTP访问方法,如果没有指定则所有方法都被保护.如果声明,当用户以这种方式访问时,要求通过安全验证 |
<auth-constraint> | 声明可访问资源的角色,可以定义多个角色 |
<role-name> | 指定角色 |
login-config
login-cofig定义当用户访问受保护资源时弹出的登录对话框类型.如下定义:
<login-config>
<auth-method>FORM</auth-method>
<realm-name>安全登录验证</realm-name>
<form-login-config>
<form-login-page>/login.jsp</form-login-page>
<form-error-page>/error.jsp</form-error-page>
</form-login-config>
</login-config>
其中各个属性如下:
<auth-method> | 指定验证方法,有三种可选:BASIC,DIGEST,FORM |
<realm-name> | 安全域名称 |
<form-login-config> | 当验证方法为form时,配置验证网页和出错网页 |
<form-login-page> | 当验证方法为form时,验证的页面 |
<form-error-page> | 当验证方法为form时,出错时的页面 |
基本验证:BASIC
如果采用这个验证,在用户访问时浏览器会弹出一个对话框,要求用户输入用户名和密码.如果输入正确,就允许他访问,如果三次输入验证失败,会显示一个错误消息页面.这个方法的缺点是把用户名和密码从客户端传到服务端时在网络上传送采用Base64编码(全是可读文本),因此不安全,配置代码如:
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>安全登录验证</realm-name>
</login-config>
摘要验证:DIGEST
摘要方法验证不会在网络中传输用户名和密码,而是采用MD5对信息进行加密,然后传输加密后的内容.其他的都是一样.配置如下:
<login-config>
<auth-method>DIGEST</auth-method>
<realm-name>安全登录验证</realm-name>
</login-config>
表单验证:FORM
它使用自定义的表单页面来进行验证.而且可以配置验证失败后显示的页面.
用户自定义的表单页面中必须包括名为:j_username的用户名输入框和名为j_password的密码输入框.且表单的action值必须是:j_security_check
security-role
在web.xml中加入该元素.指明这个web应用引用的所有角色.如:
<security-role>
<description>描述</description>
<role-name>admin</role-name>
</security-role>
当然,admin这个角色事先必须在tomcat中配置好.这里只是表明要对它进行引用.
内存域
由org.apache.catalina.realm.MemoryRealm类实现.MemoryRealm类从一个XML文件读取用户用户信息.默认情况下,该XML为:tomcat安装目录下的conf/tomcat-users.xml.<role>元素用来定义角色.<tomcat-users>用来设定用户信息.如:
<tomcat-users>
<user name="admin" password="admin"roles="admin,manager" />
<user username="tomcat" password="tomcat"roles="tomcat"/>
<user username="role1" password="tomcat"roles="role1"/>
</tomcat-users>
在server.xml中我们可以对Context元素进行配置,加入<Realm>元素.
<RealmclassName=”org.apache.catalina.realm.MemoryRealm”/>
总结起来,配置内存域的步骤:
1.在应用的web.xml中加安全约束.
2.在tomcat-usres.xml中定义用户和角色的映射关系.
3.在server.xlm中加入相应的Realm元素.
4.重启tomcat,访问页面
JDBC域
上面要求验证的地方会让我们输入用户名和密码.这些信息是在tomcat-users.xml中配置的.在服务启动时,这些信息被转换成对象,并放在内存中.但这样不够灵活.
JDBC域提供更灵活的方案,它允许我们通过JDBC访问存放在数据库中的用户信息.因此,当用户信息更改时,我们也不需要重启tomcat.
当用户第一次访问受限资源时.tomcat将调用Realm类的authenticate()方法.该方法从数据库中读取最新的安全验证信息.用户通过验证后,在用户访问WEB资源期间,用户的各种验证信息都被保存在缓存中(对于FORM类型的验证,验证信息在会话结束后失效.BASIC类型的验证在关闭浏览器时失效.)因此,如果此时对数据库中的安全验证信息做了修改,这种修改对正在访问资源的用户是无效的,只有当用户再次登录时才会生效.
数据库用户表结构
必须在数据加中建两张表:user,user_roles;
user用来保存用户名和密码.user_roles定义用户和角色的映射.一个用户可以没有角色,也可以有一个或多个角色.
在MYSQL中创建表
createdatabase tomcatusers
CREATETABLE`users`(
`user_name`VARCHAR(15)NOTNULL,
`user_pass`VARCHAR(15)NOTNULL,
PRIMARYKEY(`user_name`)
)
CREATETABLE`users_roles`(
`user_name`VARCHAR(15)NOTNULL,
`role_name`VARCHAR(15)NOTNULL,
PRIMARYKEY(`user_name`, ` role_name `)
)
insertinto users values(“sunyu”,”123456”);
insertinto users values(“xingping”,”123456”);
insertinto user_roles values(“sunyu”,”guest”);
insertinto user_roles values(“xingping”,”friend”);
配置Realm
建好表后,将MYSQL数据库驱动程序复制到TOMCAT安装目录下的:lib 下.然后在server.xml中项目对应的Context元素中加入如下:
<RealmclassName=”org.apache.catalina.realm.JDBCRealm”driverName=”com.mysql.jdbc.Driver” debug=”99”connectionURL=”jdbc:mysql://localhost/tomcatusers”connectionName=”root” connectionPassword=”123456” userTable=”users”userNameCol=”user_name” userCredCol=”user_pass”userRoleTable=”user_roles” roleNameCol=”role_name”/>
DataSource域
和JDBC域的用法相似,也是放在数据库.不过学里不是通过JDBC访问数据库,而是通过JNDI DataSource访问.步骤:
1.在web.xlm中加约束.
2.同上面一样,建立表,添加数据.
3.将MySql驱动复制到lib下.
4.在server.xlm中建立一个数据源.
5.在项目中加<Realm>
6.启动tomcat.
<GlobalNamingResources>
<Resource name=" jdbc/tomcatusers "auth="Container"
type="javax.sql.DataSource" />
<ResourceParams name=”jdbc/tomcatusers”>
<parameter>
<name>factory</name>
<value>org.apache.comons.dbcp.BasicDataSourceFactory</value>
</parameter>
<parameter>
<name>maxActive</name>
<value>100</value>
</parameter>
<parameter>
<name>maxIdle</name>
<value>30</value>
</parameter>
<parameter>
<name>maxWait</name>
<value>10000</value>
</parameter>
<parameter>
<name>username</name>
<value>root</value>
</parameter>
<parameter>
<name>password</name>
<value>123456</value>
</parameter>
<parameter>
<name>driverClassName</name>
<value>com.mysql.jdbc.Driver</value>
</parameter>
<parameter>
<name>url</name>
<value>jdbc:mysql://lcoalhost:3306/tomcatusers?autoReconnect=true</value>
</parameter>
</ ResourceParams>
</GlobalNamingResources>
参考配置文件:
<RealmclassName=”org.apache.catalina.DataSourceRealm” debug=”99”dataSourceName=”jdbc/tomcatusers” userTable=”users”userNameCol=”user_name” userCredCol=”user_pass”userRoleTable=”user_roles” roleNameCol=”role_name”/>