Java WEB 安全认证

用户权限问题是绝大部分应用都要考虑的问题,在这些应用中想必都会定义role,user等来控制资源的访问。今天这里要说的并不是如何去设计权限的管理系统,而是来说明一下Web应用的安全域等。

在与Java web相关的JSR中,对于Java Web的安全访问有也相关规定,具体内容就不再这里阐述。与些相关的配置有:security-constraint,security-role,login-config。

Web安全访问的机制其实就是一套权限处理系统。它包括了:role、user、resources、group等概念。接下来就心Tomcat的manager应用为例来了解一下web安全相关内容。

1、在Web.xml中使用security-role定义角色

在Manager应用在web.xml中定义了下列角色:

<security-role>
    <description>
      The role that is required to access the HTML Manager pages
    </description>
    <role-name>manager-gui</role-name>
  </security-role>
  <security-role>
    <description>
      The role that is required to access the text Manager pages
    </description>
    <role-name>manager-script</role-name>
  </security-role>
  <security-role>
    <description>
      The role that is required to access the HTML JMX Proxy
    </description>
    <role-name>manager-jmx</role-name>
  </security-role>
  <security-role>
    <description>
      The role that is required to access to the Manager Status pages
    </description>
    <role-name>manager-status</role-name>
  </security-role>
  <security-role>
    <description>
      Deprecated role that can access all Manager functionality
    </description>
    <role-name>manager</role-name>
  </security-role>

从上面的例子中,就直接可以看出角色定义是很简单的,只需要设置role-name就可以了。

2、在web.xml中使用security-constraint配置资源访问

Manager应用中定义了一些安全访问的限制如下:

<security-constraint>
    <web-resource-collection>
      <web-resource-name>Manager commands</web-resource-name>
      <url-pattern>/list</url-pattern>
      <url-pattern>/expire</url-pattern>
      <url-pattern>/sessions</url-pattern>
      <url-pattern>/start</url-pattern>
      <url-pattern>/stop</url-pattern>
      <url-pattern>/install</url-pattern>
      <url-pattern>/remove</url-pattern>
      <url-pattern>/deploy</url-pattern>
      <url-pattern>/undeploy</url-pattern>
      <url-pattern>/reload</url-pattern>
      <url-pattern>/save</url-pattern>
      <url-pattern>/serverinfo</url-pattern>
      <url-pattern>/roles</url-pattern>
      <url-pattern>/resources</url-pattern>
      <url-pattern>/findleaks</url-pattern>
    </web-resource-collection>
    <auth-constraint>
       <!-- NOTE: 1. These roles are not present in the default users file
                  2. The manager role is deprecated, it will be removed in
                     Tomcat 7.
                  3. Use the manager-script role to take advantage of the new
                     CSRF protection. Using the manager role or assigning both
                     the manager-script and manager-gui roles to the same user
                     will bypass the CSRF protection. -->
       <role-name>manager-script</role-name>
       <role-name>manager</role-name>
    </auth-constraint>
  </security-constraint>

  <security-constraint>
    <web-resource-collection>
      <web-resource-name>HTML Manager commands</web-resource-name>
      <url-pattern>/html/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
       <!-- NOTE: 1. These roles are not present in the default users file
                  2. The manager role is deprecated, it will be removed in
                     Tomcat 7.
                  3. Use just the manager-gui role to take advantage of the new
                     CSRF protection. Assigning the manager role or manager-gui
                     role along with either the manager-script or manager-jmx
                     roles to the same user will bypass the CSRF protection. -->
       <role-name>manager-gui</role-name>
       <role-name>manager</role-name>
    </auth-constraint>
  </security-constraint>

  <security-constraint>
    <web-resource-collection>
      <web-resource-name>JMX proxy</web-resource-name>
      <url-pattern>/jmxproxy/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
       <!-- NOTE: 1. These roles are not present in the default users file
                  2. The manager role is deprecated, it will be removed in
                     Tomcat 7.
                  3. Use the manager-jmx role to take advantage of the new
                     CSRF protection. Using the manager role or assigning both
                     the manager-jmx and manager-gui roles to the same user
                     will bypass the CSRF protection. -->
       <role-name>manager-jmx</role-name>
       <role-name>manager</role-name>
    </auth-constraint>
  </security-constraint>

  <security-constraint>
    <web-resource-collection>
      <web-resource-name>Status</web-resource-name>
      <url-pattern>/status/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
       <!-- NOTE: 1. These roles are not present in the default users file
                  2. The manager role is deprecated, it will be removed in
                     Tomcat 7. -->
       <role-name>manager-status</role-name>
       <role-name>manager-gui</role-name>
       <role-name>manager-script</role-name>
       <role-name>manager-jmx</role-name>
       <role-name>manager</role-name>
    </auth-constraint>
  </security-constraint>

从上面的例子中很容易可以理解:security-constraint是用于对指定的角色进行url资源访问上的限制。

3、使用Realm来配置user

到目前为止,resources、role已经配置完毕,那么怎么去指定访问资源的用户呢?以及这些用户是拥有哪些role呢?

Realm安全域,简单的理解就是一个数据存储介质(例如xml-文件、数据库、JNDI数据源等),或者说是数据来源。它配置了username、password、所属roles的这样一个简单的数据库。

第一种服务器中间件都会支持多种Realm的配置方式。这里只说一下在使用Tomcat时,可以基于哪些数据存储介质来配置:

相信看了这个类的继承关系图,就可以知道Tomcat中支持哪些配置Realm的方式了。

MemoryRealm 是使用tomcat/conf/tomcat-users.xml来配置的。

JNDIRealm 是基于JNDI资源的方式配置的,

JDBCRealm 是将用户存储在数据库里。

3.1  JDBCRealm

在一个数据库里创建下面两张表:

create table users (
  user_name         varchar(15) not null primary key,
  user_pass         varchar(15) not null
);

create table user_roles (
  user_name         varchar(15) not null,
  role_name         varchar(15) not null,
  primary key (user_name, role_name)
);

然后在tomcat/conf/server.xml中配置插入数据.

<Realm className="org.apache.catalina.realm.JDBCRealm"
      driverName="org.gjt.mm.mysql.Driver"
   connectionURL="jdbc:mysql://localhost/authority?user=dbuser;password=dbpass"
       userTable="users" userNameCol="user_name" userCredCol="user_pass"
   userRoleTable="user_roles" roleNameCol="role_name"/>


3.2 DataSourceRealm

在tomcat中定义数据源的方式就是使用JNDI Resources。

1、创建相关表

create table users (
  user_name         varchar(15) not null primary key,
  user_pass         varchar(15) not null
);

create table user_roles (
  user_name         varchar(15) not null,
  role_name         varchar(15) not null,
  primary key (user_name, role_name)
);

2、server.xml配置一个Global Resources or Context Resources

<Resource name="jdbc/authority" auth="Container"
            type="javax.sql.DataSource"
username="dbuser" password="dbpass" url= "jdbc:mysql://localhost/authority?useEncoding=UTF-8"
/>

如果不会配置datasource可以参考Tomcat:定义JNDI资源,访问数据库

3、在server.xml中配置Realm

<Realm className="org.apache.catalina.realm.DataSourceRealm"
   dataSourceName="jdbc/authority"
   userTable="users" userNameCol="user_name" userCredCol="user_pass"
   userRoleTable="user_roles" roleNameCol="role_name"/>


3.3 JNDIRealm

虽然tomcat中使用resource定义的资源都是通过jndi方式来访问的,但是这里说的JNDIRealm是特指使用了LDAP 目录服务的数据源。

3.4 UserDatabaseRealm

UserDatabaseRealm是Realm的一个子类,它是通过JNDI资源的方式来获取数据的。所以需要采用Resource的定义方式来定义。例如Tomcat中默认的配置

    <Resource auth="Container" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" name="UserDatabase" pathname="conf/tomcat-users.xml" type="org.apache.catalina.UserDatabase"/>

它定义了名为UserDatabase的资源,然后在Engine范围内使用这个Realm:

<Engine defaultHost="localhost" name="Catalina">
<Realm 
className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase" />

只不过数据来源于tomcat-users.xml。

3.5 MemoryRealm

如果要使用MemoryRealm,需要在server.xml中配置相关Realm,MemoryRealm默认是使用tomcat/conf/tomcat-users.xml文件。其实也可以是其它的xml文件,只要格式与tomcat-user.xml 文件格式一样即可。也就是说,满足在tomcat-users元素下定义user(和role)即可。

<tomcat-users>
<!--
  NOTE:  By default, no user is included in the "manager-gui" role required
  to operate the "/manager/html" web application.  If you wish to use this app,
  you must define such a user - the username and password are arbitrary.
-->
<!--
  NOTE:  The sample user and role entries below are wrapped in a comment
  and thus are ignored when reading this file. Do not forget to remove
  <!.. ..> that surrounds them.
-->

  <role rolename="tomcat"/>
  <role rolename="role1"/>

  <user username="both" password="tomcat" roles="tomcat,role1"/>
  <user username="role1" password="tomcat" roles="role1"/>

    <user username="tomcat" password="tomcat" roles="manager-gui,manager" />
    <user username="tomcat2" password="tomcat" roles="manager-gui,manager" />
    <user username="tomcat3" password="tomcat" roles="manager-gui,manager" />
    <user username="tomcat4" password="tomcat" roles="manager-gui,manager" />
</tomcat-users>


3.6 JAASRealm

如果你了解JAAS的话,JAASRealm的方式你就很容易学会的。JAAS 是Java Authentication & Authorization Service (JAAS) framework ,是J2SE API的一部分。这个就不再详细说明。

3.7 CombinedRealm

顾名思义,就是结合了多种Realm方式。例如:

<Realm className="org.apache.catalina.realm.CombinedRealm" >
    <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
             resourceName="UserDatabase"/>
    <Realm className="org.apache.catalina.realm.DataSourceRealm"
             dataSourceName="jdbc/authority"
             userTable="users" userNameCol="user_name" userCredCol="user_pass"
             userRoleTable="user_roles" roleNameCol="role_name"/>

</Realm>

3.8 LockOutRealm

LockOutRealm 是 CombinedRealm的子类,它额外的提供了锁出机制。这里就不再详细说明了。

4 认证方式

到目前为此,user( & group) 、role、resouces都配置完毕了,那么要让服务器采用哪种认证方式呢?

目前的服务器中间件都支持下列几种方式: BASIC、DIGEST、CLIENT_CERT、FORM。这几种方式是标准的。

对于tomcat来说,它同样也支持这几种。

要配置采用哪种认证方式很简单,只需要在web.xml的login-config中配置认证方式为上面几种即可。下面来简单的分别说一下这几种认证方式。

4.1 BASIC

Basic方式是最简单的方式,用户若访问受限的资源时,浏览器就会弹出一个对话框,让输入用户名和密码。浏览器在发送请求时,会使用Base64进行编码。

<login-config>
        <auth-method>BASIC</auth-method>
    </login-config>

查看认证过程的部分源码:

if (authorization != null) {
            authorization.toBytes();
            ByteChunk authorizationBC = authorization.getByteChunk();
            if (authorizationBC.startsWithIgnoreCase("basic ", 0)) {
                authorizationBC.setOffset(authorizationBC.getOffset() + 6);
                // FIXME: Add trimming
                // authorizationBC.trim();

                CharChunk authorizationCC = authorization.getCharChunk();
                Base64.decode(authorizationBC, authorizationCC);

                // Get username and password
                int colon = authorizationCC.indexOf(‘:‘);
                if (colon < 0) {
                    username = authorizationCC.toString();
                } else {
                    char[] buf = authorizationCC.getBuffer();
                    username = new String(buf, 0, colon);
                    password = new String(buf, colon + 1,
                            authorizationCC.getEnd() - colon - 1);
                }

                authorizationBC.setOffset(authorizationBC.getOffset() - 6);
            }

            principal = context.getRealm().authenticate(username, password);
            if (principal != null) {
                register(request, response, principal, Constants.BASIC_METHOD,
                         username, password);
                return (true);
            }
        }
        

认证前,使用Base64解码取得用户名和密码,然后进行认证。

4.2 FORM

使用FORM方式时,就需要在自己定制登录页面:

<login-config>
        <auth-method>FORM</auth-method>
        <form-login-config>
            <form-login-page>/login.html</form-login-page>
            <form-error-page>/error.jsp</form-error-page>
        </form-login-config>
    </login-config>

login页面如下:

<form name="loginform" method="post" action="j_security_check">
<INPUT name="j_username" type="text">
<INPUT name="j_password" TYPE="password">
<input type="submit" value="登 录" >
</form>

其中表单的action值,以及代表用户名、密码的input的name值是固定的。

下面是部分源码:

String username = request.getParameter(Constants.FORM_USERNAME);
        String password = request.getParameter(Constants.FORM_PASSWORD);
        if (log.isDebugEnabled())
            log.debug("Authenticating username ‘" + username + "‘");
        principal = realm.authenticate(username, password);
        if (principal == null) {
            forwardToErrorPage(request, response, config);
            return (false);
        }

认证失败就会转到error-page了。

4.3 DIGEST

<login-config>
        <auth-method>DIGEST</auth-method>
    </login-config>

Digest,采用的是MD5摘要算法。可以参考源码:

            // Second MD5 digest used to calculate the digest :
            // MD5(Method + ":" + uri)
            String a2 = method + ":" + uri;

            byte[] buffer;
            synchronized (md5Helper) {
                buffer = md5Helper.digest(a2.getBytes());
            }
            String md5a2 = md5Encoder.encode(buffer);

            return realm.authenticate(userName, response, nonce, nc, cnonce,
                    qop, realmName, md5a2);

4.4 CLIENT_CERT

<login-config>
        <auth-method>CLIENT-CERT</auth-method>
    </login-config>

采用的是X509证书认证。

5、安全认证流程

当用户访问的是一个受限的资源(也就是security-contistans中配置的url)时,应付触发安全认证。安全认证的过程:Server通过不同形式(基于认证方式的不同)取得用户的username和password,与Realm中存储的值匹配,匹配成功后就得知访问用户所拥有的roles,再根据roles判断是否能够访问的资源。如果这些流程都通过,会将用户信息存储在session中,这样就不需要每次访问受限资源都输入用户名和密码,之后就能够访问到资源了。中间过程有一步出错,就会访问失败。

时间: 2024-10-25 04:13:21

Java WEB 安全认证的相关文章

java web项目war包部署,使用tomcat对指定接口设置身份认证

先简单说一下需求: 将一个基于springboot2.0开发的java web项目打成war包,通过tomcat部署到一台linux服务器上,项目相关的一些图片等资源也按照一定规则放置在服务器构建好的目录下.现在需要让用户通过http网页链接的方式(在浏览器端)访问图片,为了访问安全,需要在中间加一层用户认证.认证过程希望尽量简单些,所以就尝试用tomcat自带的身份认证来做. 话不多说,直接上实现流程: 首先,由于要访问本地的静态资源,所以在springboot启动类中加了一项静态资源的映射,

[Java Web]2\Web开发中的一些架构

1.企业开发架构: 企业平台开发大量采用B/S开发模式,不管采用何种动态Web实现手段,其操作形式都是一样的,其核心操作的大部分都是围绕着数据库进行的.但是如果使用编程语言进行数据库开发,要涉及很多诸如事务.安全等操作问题,所以现在开发往往要通过中间件进行过渡,即,程序运行在中间件上,并通过中间件进行操作系统的操作,而具体一些相关的处理,如事务.安全等完全由中间件来负责,这样程序员只要完成具体的功能开发即可. 2.Java EE架构: Java EE 是在 Java SE 的基础上构建的,.NE

Java Web系列:Spring Security 基础

Spring Security虽然比JAAS进步很大,但还是先天不足,达不到ASP.NET中的认证和授权的方便快捷.这里演示登录.注销.记住我的常规功能,认证上自定义提供程序避免对数据库的依赖,授权上自定义提供程序消除从缓存加载角色信息造成的角色变更无效副作用. 1.基于java config的Spring Security基础配置 (1)使用AbstractSecurityWebApplicationInitializer集成到Spring MVC 1 public class Securit

关于Java Web应用中的配置部署描述符web.xml

一.web.xml概述 位于每个Web应用的WEB-INF路径下的web.xml文件被称为配置描述符,这个 web.xml文件对于Java Web应用十分重要,每个Java Web应用都必须包含一个web.xml文件,且必须放在WEB-INF路径下. 对于Java Web应用而言,WEB-INF是一个特殊的文件夹,Web容器会包含该文件夹下的内容,客户端浏览器无法访问WEB-INF路径下的任何内容.Java Web应用的绝大部分内容都由web.xml文件来配置管理.我们后面介绍的如下内容都要通过

Tomcat:Java Web服务器配置详解

一.Tomcat概述 1.tomcat简介 tomcat是基于JDK的web服务器,其能运行Servlet和JSP规范总.Tomcat 5支持最新的Servlet 2.4 和JSP 2.0规范.实际上Tomcat 部分是Apache服务器的扩展,但它是独立运行的.运行tomcat时,它实际上作为一个与Apache 独立的进程单独运行的.Apache 为HTML页面服务,而Tomcat实际上运行JSP页面和Servlet.tomcat具有处理HTML页面的功能,另外它还是一个Servlet和JSP

jHipster 3.4 创建最流行Java Web应用项目最简单的入门基本教程

jHipster(J潮客)其亮点: 风头超劲,席卷欧美,最新全能Java Web开发程式产生器 (java web generator). 由Java专家累积的开发经验,配上各类实用的框架技术,去繁取精的运用,全方位的配置,制成出完备的开发应用程式. 完美Java体系架构,适合各行各业项目,尤其以适用于面向服务的体系结构(SOA)更为胜任. 不论菜鸟,老牛或专家,极容易上手,只要你可以下载及建立以下要求的工作环境. 快速建成一个制作就绪的基本项目工作模版,令你可以用有限的精力专注业务上的运作.

跟阿根一起学Java Web开发四:邮件发送与短信发送的实现

邮件发送与短信发送常见于用户注册认证以及系统消息提示功能模块,但实现代码过于繁琐:使用JSPGen后,深感其对邮件发送.短信发送的封装让复杂活变得简单很多. 一.基础配置 1.jspgen-config.xml 在框架基础配置文件中,找到mail节点及sms节点,按如下配置: <!-- 邮件服务 --> <mail status="true"> <smtp> <!-- 发送类型(SMTP MX) --> <type>SMTP&

基于JAVA WEB技术旅游服务网站系统设计与实现网上程序代写

基于JAVA WEB技术旅游服务网站系统设计与实现网上程序代写 专业程序代写服务(QQ:928900200) 随着社会的进步.服务行业的服务水平不断发展与提高,宾馆.酒店.旅游等服务行业的信息量和工作量日益变大,而传统的人工管理方式已经远远不能满足现在旅游的服务方式.传统的旅游方式经分析其有诸多的缺陷,存在数据维护效率低下,不易保管,容易丢失和出错.同时查询也不方便,劳动力成本过高导致的旅游资源信息不方便,也在一定程度上导致了对各种信息反应缓慢,容易丧失商机.为了弥补上述缺陷,便于开展旅游预订工

java web验证码生成总结(包括servlet、jsp和struts2实现)(转)

一.使用纯Servlet实现验证码 (1)在web.xml配置: [java] view plaincopy <servlet> <servlet-name>image</servlet-name> <servlet-class>org.test.web.AuthImage</servlet-class> </servlet> <servlet-mapping> <servlet-name>image</