Glassfish 3安全性 - 使用JDBC领域进行基于表单的身份验证

24
我希望了解基于表单的安全和JDBC领域在glassfishV3中的应用,于是我决定创建一个简单的应用程序,只允许登录和退出,我按照这本书籍的说明进行操作。
我理解整个过程如何运作,但是有些问题出现了,我无法使其正常工作。
首先我创建了一个带有JPA注释的小型数据库。
@Entity
@Table(name="USERS")
public class User implements Serializable {

    private static final long serialVersionUID = -1244856316278032177L;
    @Id
    @GeneratedValue
    @Column(nullable = false)
    private Long id;
    @Column(nullable = false)
    private String email;
    @Column(nullable = false)
    private String password;
    @OneToMany(mappedBy = "user")
    private List<Group> groups;
    //GET & SET METHODS...

}

这里是另一个表格,用于保存每个用户的角色

@Entity
@Table(name="GROUPS")
public class Group implements Serializable {

    private static final long serialVersionUID = -7274308564659753174L;
    @Id
    @GeneratedValue
    @Column(nullable = false)
    private Long id;
    @Column(nullable = false)
    private String groupName;
    @ManyToOne
    @JoinColumn(name = "USERS_ID", nullable = false)
    private User user;
    //GET & SET METHODS...
    }

当数据库准备好后,我手动添加了一些数据。

enter image description here

下一步是配置安全域。

enter image description here

然后将安全配置添加到我的web.xml文件中

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    version="3.0">

    <display-name>CHAPTER x 12 Container Managed Authentication and
        Authorization</display-name>
    <welcome-file-list>
        <welcome-file>index.xhtml</welcome-file>
    </welcome-file-list>
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.xhtml</url-pattern>
    </servlet-mapping>

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>VISITOR PERMISIONS</web-resource-name>           
            <url-pattern>/index.xhtml</url-pattern>         
            <url-pattern>/visitorpanel.xhtml</url-pattern>
            <http-method>GET</http-method>
            <http-method>POST</http-method>
        </web-resource-collection>
        <auth-constraint>
            <role-name>visitors</role-name>
            <role-name>users</role-name>
            <role-name>administrators</role-name>
        </auth-constraint>
    </security-constraint>

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>USERS PERMISIONS</web-resource-name>         
            <url-pattern>/userpanel.xhtml</url-pattern>
            <url-pattern>/index.xhtml</url-pattern>         
            <url-pattern>/visitorpanel.xhtml</url-pattern>
            <http-method>GET</http-method>
            <http-method>POST</http-method>         
        </web-resource-collection>
        <auth-constraint>           
            <role-name>users</role-name>
            <role-name>administrators</role-name>
        </auth-constraint>
    </security-constraint>

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>ADMIN PERMISIONS</web-resource-name>             
            <url-pattern>/adminpanel.xhtml</url-pattern>
            <url-pattern>/userpanel.xhtml</url-pattern>
            <url-pattern>/index.xhtml</url-pattern>         
            <url-pattern>/visitorpanel.xhtml</url-pattern>          
            <http-method>GET</http-method>
            <http-method>POST</http-method>
        </web-resource-collection>
        <auth-constraint>           
            <role-name>administrators</role-name>
        </auth-constraint>
    </security-constraint>

    <login-config>
        <auth-method>FORM</auth-method>
        <realm-name>DBRealm</realm-name>
        <form-login-config>
            <form-login-page>/index.xhtml</form-login-page>
            <form-error-page>/error.xhtml</form-error-page>
        </form-login-config>
    </login-config>

    <security-role>
    <role-name>visitors</role-name>
    </security-role>

    <security-role>
    <role-name>users</role-name>
    </security-role>

    <security-role>
    <role-name>administrators</role-name>
    </security-role>
</web-app>

我的目标是:

  • 管理员可以看到所有页面

  • 访客只能看到index.xhtml和visitorpanel.xhtml

  • 用户可以看到index.xhtml、visitorpanel.xhtml和userpanel.xhtml

我认为配置是正确的。

最后一步是在index.xhtml页面创建登录表单:

<form method="post" action="j_security_check" name="loginForm">

        <h:outputLabel id="userNameLabel" for="j_username" value="Enter your em@il:"/>
        <h:inputText id="j_username" autocomplete="off" />
        <br/>
        <h:outputLabel id="passwordLabel" for="j_password" value="Enter your em@il password:"/>
        <h:inputSecret id="j_password" autocomplete="off"/>
        <br/>
        <h:commandButton type="submit" value="Login"/>
        <h:commandButton type="reset" value="Clear"/>
  </form>

程序构建成功,但我遇到以下问题:
1- 当我尝试以用户或管理员身份登录时(访问者无需登录),我被重定向到error.xhtml页面,并且在控制台中看到一个异常:
SEVERE:SEC1112:无法验证JDBC领域的用户[admin@gmail.com]。警告:Web登录失败:登录失败:javax.security.auth.login.LoginException:安全异常警告:PWC4011:无法将请求字符编码设置为UTF-8,因为请求参数已经被读取,或者已经调用了ServletRequest.getReader()
2- 当我尝试通过URL导航到某些页面时,什么也不发生。我认为这是正常的,但当我尝试访问visitorpanel.xhtml时,它应该允许我访问,因为不需要登录即可查看它。 如果我想让每个人都看到它,我需要从安全配置中删除该页面吗?
3- 另外,我很好奇为什么在实现登录时不能使用h:form标签而只能使用form标签?
我真的很感激一些帮助,我已经花费了几个小时阅读书籍的前几章并尝试实现自己的示例,但我卡住了。 我认为我接近解决方案。
更新
我将默认主体更改为访客用户名。 但仍然无法正常工作。

enter image description here

我还向我的Realm配置中添加了一些选项。

enter image description here

但是当我尝试登录时,仍然看到一个异常,内容如下:

SEVERE: SEC1112: 无法为JDBC域验证用户[admin@gmail.com]。警告:Web登录失败:登录失败:javax.security.auth.login.LoginException:安全异常警告:PWC4011:无法将请求字符编码设置为UTF-8,因为请求参数已被读取,或者已经调用了ServletRequest.getReader()

我仍然不知道缺少什么。

- 是表名不应该是大写吗?

- 是列名不应该是大写的吗?

- 是表创建有问题吗?

- 是因为我不能使用PASSWORD作为列名,因为它会产生某种冲突吗?

我真的不明白为什么会出现这个异常。我从管理面板ping了数据库,一切似乎都正确。

有人可以帮我解决这个问题吗?

更新2

我将'javax.enterprise.system.core.security'日志选项更改为FINE级别,以在异常发生时获得更多信息,当我尝试登录时,结果如下:

FINE: 拦截条目: 拦截: SOAP 默认服务器ID: null 默认客户端ID: null FINE: ID条目: 模块类: com.sun.xml.wss.provider.ClientSecurityAuthModule ID: XWS_ClientProvider 类型: 客户端 请求策略: javax.security.auth.message.MessagePolicy@e95a72 响应策略: javax.security.auth.message.MessagePolicy@310a6d 选项: {signature.key.alias=s1as, debug=false, dynamic.username.password=false, encryption.key.alias=s1as} FINE: ID条目: 模块类: com.sun.xml.wss.provider.ClientSecurityAuthModule ID: ClientProvider 类型: 客户端 请求策略: javax.security.auth.message.MessagePolicy@1829770 响应策略: javax.security.auth.message.MessagePolicy@a4461e 选项: {signature.key.alias=s1as, debug=false, dynamic.username.password=false, encryption.key.alias=s1as, security.config=C:\jeeAplicationServer\glassfishv3\glassfish\domains\domain1/config/wss-server-config-1.0.xml} FINE: ID条目: 模块类: com.sun.xml.wss.provider.ServerSecurityAuthModule ID: XWS_ServerProvider 类型: 服务器 请求策略: javax.security.auth.message.MessagePolicy@f79c86 响应策略: javax.security.auth.message.MessagePolicy@454bf7 选项: {signature.key.alias=s1as, debug=false, encryption.key.alias=s1as} FINE: ID条目: 模块类: com.sun.xml.wss.provider.ServerSecurityAuthModule ID: ServerProvider 类型: 服务器 请求策略: javax.security.auth.message.MessagePolicy@17e85e4 响应策略: javax.security.auth.message.MessagePolicy@1887906 选项: {signature.key.alias=s1as, debug=false, encryption.key.alias=s1as, security.config=C:\jeeAplicationServer\glassfishv3\glassfish\domains\domain1/config/wss-server-config-1.0.xml} FINE: [Web-Security] 设置策略上下文ID: 旧值 = null ctxID = CHAPTER_x_12_Container_Managed_Authentication_and_Authorization/CHAPTER_x_12_Container_Managed_Authentication_and_Authorization FINE: [Web-Security] hasUserDataPermission 权限: (javax.security.jacc.WebUserDataPermission /j_security_check POST) FINE: [Web-Security] hasUserDataPermission 是否授权: true FINE: 登录用户[admin@gmail.com]到域: DBRealm 使用JAAS模块: jdbcRealm FINE: 登录模块已初始化: 类 com.sun.enterprise.security.auth.login.JDBCLoginModule SEVERE: SEC1112: 无法为JDBC realm验证用户[admin@gmail.com]. FINE: 无法验证用户 javax.security.auth.login.LoginException: 无法连接到数据源jdbc/security的数据库用户user。 at com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm.getConnection(JDBCRealm.java:550) at com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm.isUserValid(JDBCRealm.java:393) at com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm.authenticate(JDBCRealm.java:311) at com.sun.enterprise.security.auth.login.JDBCLoginModule.authenticate(JDBCLoginModule.java:72) at com.sun.enterprise.security.auth.login.PasswordLoginModule.authenticateUser(PasswordLoginModule.java:90) at com.sun.appserv.security.AppservPasswordLoginModule.login(AppservPasswordLoginModule.java:141) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at javax.security.auth.login.LoginContext.invoke(LoginContext.java:769) at javax.security.auth.login.LoginContext.access$000(LoginContext.java:186) at javax.security.auth.login

更新 3

也许连接池出了问题。 这是我的连接池的样子:

enter image description here

enter image description here

enter image description here

我没有太多属性,可能有些东西缺失了吗?

现在我创建了一个JDBC资源,看起来像这样:

enter image description here

领域中的JNDI名称已更改为jdbc/studydb。

我的persistence.xml看起来像这样:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
    <persistence-unit name="CHAPTER x 12 Container Managed Authentication and Authorization">
        <jta-data-source>jdbc/studydb</jta-data-source>     
        <class>entities.User</class>
        <class>entities.Group</class>
    </persistence-unit>
</persistence>

我认为我取得了一些进展,现在我看到的异常是:

> SEVERE: jdbcrealm.invaliduserreason
>      FINE: Cannot validate user
>      java.sql.SQLSyntaxErrorException: Schema 'ADMIN' does not exist
>       at org.apache.derby.client.am.SQLExceptionFactory40.getSQLException(Unknown
> Source)
>      ....
>      
>      Caused by: org.apache.derby.client.am.SqlException: Schema 'ADMIN' does not exist
>       at org.apache.derby.client.am.Statement.completeSqlca(Unknown Source)
>      ...
>      FINE: JAAS authentication aborted.
>      WARNING: Web login failed: Login failed: javax.security.auth.login.LoginException: Security Exception
>      FINE: [Web-Security] Policy Context ID was: CHAPTER_x_12_Container_Managed_Authentication_and_Authorization/CHAPTER_x_12_Container_Managed_Authentication_and_Authorization
>      FINE: [Web-Security] hasUserDataPermission perm: (javax.security.jacc.WebUserDataPermission /error.xhtml GET)
>      FINE: [Web-Security] hasUserDataPermission isGranted: true
>      WARNING: PWC4011: Unable to set request character encoding to UTF-8 from context 
> /CHAPTER_12_x_Container_Managed_Authentication_and_Authorization, 
> because request parameters have already been read, or 
> ServletRequest.getReader() has already been called

更新4

我更改了数据库,因为它的组织方式有误,所以我对实体进行了一些更改:

@Entity
    @Table(name="USERS", schema="ADMIN")
    public class User implements Serializable {

        private static final long serialVersionUID = -1244856316278032177L;
        @Id 
        @Column(nullable = false)
        private String userid;  

        @Column(nullable = false)
        private String password;

        @ManyToOne
        @JoinTable(name="USER_GROUP",schema="ADMIN", joinColumns = @JoinColumn(name="userid", referencedColumnName="userid"), inverseJoinColumns=@JoinColumn(name="groupid", referencedColumnName= "groupid") )
        private Group group;
        //GET & SET METHODS

@Entity @Table(name="GROUPS", schema="ADMIN") public class Group implements Serializable {

实体类注解,指定表名为"GROUPS",模式为"ADMIN"。该类实现序列化接口。
private static final long serialVersionUID = -7274308564659753174L;
@Id
@Column(nullable = false)
private String groupid;

@OneToMany(mappedBy="group")
private Set<User> users;

//获取和设置方法

因此,我还需要编辑DBRealm,现在它看起来像这样:

enter image description here

但是当我登录时,我再次遇到了异常:
FINE: [Web-Security] Policy Context ID was: CHAPTER_x_12_Container_Managed_Authentication_and_Authorization/CHAPTER_x_12_Container_Managed_Authentication_and_Authorization
FINE: [Web-Security] hasUserDataPermission perm: (javax.security.jacc.WebUserDataPermission /j_security_check POST)
FINE: [Web-Security] hasUserDataPermission isGranted: true
FINE: Logging in user [user@gmail.com] into realm: DBRealm using JAAS module: jdbcRealm
FINE: Login module initialized: class com.sun.enterprise.security.auth.login.JDBCLoginModule
SEVERE: SEC1111: Cannot load group for JDBC realm user [user@gmail.com].
FINE: Cannot load group
java.sql.SQLSyntaxErrorException: Column 'USERID' is either not in any table in the FROM list or appears within a join specification and is outside the scope of the join specification or appears in a HAVING clause and is not in the GROUP BY list. If this is a CREATE or ALTER TABLE  statement then 'USERID' is not a column in the target table.
....
....
Caused by: org.apache.derby.client.am.SqlException: Column 'USERID' is either not in any table in the FROM list or appears within a join specification and is outside the scope of the join specification or appears in a HAVING clause and is not in the GROUP BY list. If this is a CREATE or ALTER TABLE  statement then 'USERID' is not a column in the target table.
    at org.apache.derby.client.am.Statement.completeSqlca(Unknown Source)
....
....
FINE: JAAS login complete.
FINE: JAAS authentication committed.
FINE: Password login succeeded for : user@gmail.com
FINE: permission check done to set SecurityContext
FINE: Set security context as user: user@gmail.com
FINE: [Web-Security] Policy Context ID was: CHAPTER_x_12_Container_Managed_Authentication_and_Authorization/CHAPTER_x_12_Container_Managed_Authentication_and_Authorization
FINE: [Web-Security] hasUserDataPermission perm: (javax.security.jacc.WebUserDataPermission  GET)
FINE: [Web-Security] hasUserDataPermission isGranted: true
FINE: permission check done to set SecurityContext
FINE: SecurityContext: setCurrentSecurityContext method called

FINE: [Web-Security] Policy Context ID was: CHAPTER_x_12_Container_Managed_Authentication_and_Authorization/CHAPTER_x_12_Container_Managed_Authentication_and_Authorization
FINE: [Web-Security] hasUserDataPermission perm: (javax.security.jacc.WebUserDataPermission /adminpanel.xhtml GET)
FINE: [Web-Security] hasUserDataPermission isGranted: true
FINE: [Web-Security] Policy Context ID was: CHAPTER_x_12_Container_Managed_Authentication_and_Authorization/CHAPTER_x_12_Container_Managed_Authentication_and_Authorization
FINE: [Web-Security] Generating a protection domain for Permission check.
FINE: [Web-Security] Checking with Principal : user@gmail.com
FINE: [Web-Security] Checking with Principal : visitors
FINE: [Web-Security] Checking with Principal : users
FINE: [Web-Security] Checking with Principal : administrators
FINE: [Web-Security] Codesource with Web URL: file:/CHAPTER_x_12_Container_Managed_Authentication_and_Authorization/CHAPTER_x_12_Container_Managed_Authentication_and_Authorization
FINE: [Web-Security] Checking Web Permission with Principals : user@gmail.com, visitors, users, administrators
FINE: [Web-Security] Web Permission = (javax.security.jacc.WebResourcePermission /adminpanel.xhtml GET)
FINE: [Web-Security] hasResource isGranted: true
FINE: [Web-Security] hasResource perm: (javax.security.jacc.WebResourcePermission /adminpanel.xhtml GET)
FINE: SecurityContext: setCurrentSecurityContext method called

WARNING: Resource not found: com/sun/enterprise/v3/admin/adapter/theme/com/sun/webui/jsf/suntheme/images/masthead/masthead_button_over.gif

1
感谢sfrj一直坚持并提供了如此详细的经验!我也在使用Glassfish和JDBC领域安全方面遇到了麻烦。你问题中的细节对我非常有用!我确实看到了一些可疑或缺失的东西,但是我还没有让我的JDBC身份验证工作,所以我会等待从我的经验中提供细节。 - Jason
@Jason 你好,很高兴你觉得这个有趣。我在2011年就问过这个问题了。如果你看一下答案,也许你能把缺失的部分拼凑起来(还有很好的答案)。如果你对使用文件领域而不是jdbc领域感兴趣,可以看看我以前在博客中制作的这个视频教程: http://javing.blogspot.ie/2012/05/here-in-this-video-you-can-see-how-i.html - javing
感谢您的清晰和详细说明。这比大多数关于Glassfish身份验证的教程都要好。 - Oliver Watkins
我在从4.0迁移到4.1.1时遇到了问题。http://stackoverflow.com/questions/40686737/migration-from-glassfish-4-0-to-glassfish-4-1-1-jdbc-realm-issue - Bikram
4个回答

18

你的配置信息有一些缺失:

  • 密码以明文形式存储在数据库中,这很可能是不正确的。Glassfish 3.1 默认使用SHA-256算法,因此JDBC Realm将无法验证用户,因为数据库中存储的值与Realm创建的摘要不匹配。您需要在realm配置中指定明确的摘要算法,或者依赖默认值。另外,您需要确保应用程序在创建新用户或修改其密码时创建摘要。如果您希望以明文形式存储密码,则必须为摘要算法指定“none”。
  • 仅指定摘要算法是不足的。您还需要指定存储摘要的编码方式(因为摘要只是字节序列,可能无法存储为纯ASCII序列)。Glassfish支持Hex和Base64编码,默认使用Hex编码。因此您的应用程序应该在存储密码摘要之前,应用与领域配置相同的编码方式。请注意,当您指定“none”作为摘要算法以以明文形式存储密码时,无需对存储的密码进行编码(同样,您也无需指定编码);至少从阅读Glassfish源代码的角度来看是这样的。
  • 此外,用户组映射目前似乎是1:1。您可能需要使用单独的连接表来允许组与用户之间的1:N映射。
  • 您还需要确保启用了“默认主体到角色映射”选项。如果没有此选项,则需要手动将web.xml中的角色映射到您领域中的用户和组中

关于使用form而不是h:form,其根本原因是JSF运行时不允许您指定h:form标记的action属性。当编码响应时,此值由JSF运行时设置,因此,当您使用h:form标记时,无法指定j_security_check的值。文档明确说明了这一点

“action”属性的值必须是将当前视图的视图标识符传递给此应用程序的ViewHandlergetActionURL()方法的结果,然后将该字符串传递给ExternalContext上的encodeActionURL()方法的结果。

更新

根据发布的堆栈跟踪,我可以推断出在 Glassfish 领域中指定的 JNDI 数据源(在 JNDI 字段中)将被 Realm 使用,但不可用。 JDBC Realm 的先决条件之一是在 Glassfish 领域配置中注册一个 JNDI 数据源,其连接池用于连接到基础数据库。

以下是我的 Glassfish 领域配置文件(domain.xml)的片段,其中使用连接池 (GalleriaPool) 的 JNDI 数据源 (jdbc/galleriaDS),最终由 JDBC Realm (GalleriaRealm) 使用:

<domain log-root="${com.sun.aas.instanceRoot}/logs" application-root="${com.sun.aas.instanceRoot}/applications" version="12">
  <resources>
    ...
    <jdbc-connection-pool validation-table-name="SYSIBM.SYSDUMMY1" driver-classname="" datasource-classname="org.apache.derby.jdbc.ClientDataSource40" res-type="javax.sql.DataSource" description="" name="GalleriaPool" is-connection-validation-required="true" fail-all-connections="true" ping="true">
      <property name="User" value="APP"></property>
      <property name="DatabaseName" value="GALLERIA"></property>
      <property name="RetrieveMessageText" value="true"></property>
      <property name="CreateDatabase" value="true"></property>
      <property name="Password" value="APP"></property>
      <property name="ServerName" value="localhost"></property>
      <property name="Ssl" value="off"></property>
      <property name="SecurityMechanism" value="4"></property>
      <property name="TraceFileAppend" value="false"></property>
      <property name="TraceLevel" value="-1"></property>
      <property name="PortNumber" value="1527"></property>
      <property name="LoginTimeout" value="0"></property>
    </jdbc-connection-pool>
    <jdbc-resource pool-name="GalleriaPool" description="" jndi-name="jdbc/galleriaDS"></jdbc-resource>
  </resources>
  <servers>
    <server name="server" config-ref="server-config">
    ...
      <resource-ref ref="jdbc/galleriaDS"></resource-ref>
    </server>
  </servers>
  ...
  <configs>
    <config name="server-config">
    ...
      <security-service>
        <auth-realm name="GalleriaRealm" classname="com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm">
          <property name="jaas-context" value="jdbcRealm"></property>
          <property name="encoding" value="Hex"></property>
          <property name="password-column" value="PASSWORD"></property>
          <property name="datasource-jndi" value="jdbc/galleriaDS"></property>
          <property name="group-table" value="USERS_GROUPS"></property>
          <property name="charset" value="UTF-8"></property>
          <property name="user-table" value="USERS"></property>
          <property name="group-name-column" value="GROUPID"></property>
          <property name="digest-algorithm" value="SHA-512"></property>
          <property name="user-name-column" value="USERID"></property>
        </auth-realm>
        ...
      </security-service>
    </config>
    ...
  </configs>
  ...
</domain>

更新 #2 - 获取JDBC Realm针对Derby执行的SQL语句

看起来SQL查询的结构与您准备的数据库模型不匹配。您可以通过derby.language.logStatementText系统属性查看JDBC Realm针对Derby实例执行的SQL语句。该属性可以在derby.properties文件中作为静态值设置为true,并在重新启动Derby实例时生效。 derby.properties文件需要具有以下条目:

derby.language.logStatementText=true

这个文件必须放置在 Derby 实例的当前工作目录中。当前工作目录通常是包含 Derby 数据库的目录,并且可以在 Derby 启动过程中使用 derby.system.home JVM 参数明确指定:

-Dderby.system.home=C:\derby

Derby将记录所有执行的SQL语句到derby.log文件中。

根据提供的信息,我认为有一张名为GROUPS的单独表用于存储组信息,与连接表USER_GROUP不同。在这种情况下,您的领域必须配置为将Group表设置为USER_GROUP而不是GROUP;您可以通过查看JDBC领域发出的SQL查询来确认这一点。

为了澄清上述问题,JDBC领域配置中的Group字段并未用于指定存储组信息的表格。相反,它被用于指定存储组-用户映射的表格。在1:1映射中,Group表可以存储此信息,但在1:M或通常在M:M场景中,您将拥有包含映射的单独表。JDBC领域发出的SQL查询使用映射表而不是实际的组表(如果它们不同)来确定用户所属的组。


@sfrj,我想我误解了你关于默认主体的问题。你指的是哪个Glassfish配置?我不记得需要一个显式的用户ID和密码。 - Vineet Reynolds
@sfrj,如果列名为USERPASSWORD等,并且这些列是数据库中的保留或特殊单词,则可能会出现问题。如果可以执行SQL语句,则域将始终对用户进行身份验证。要启用默认角色-主体映射:要打开默认映射,请在管理控制台中选择配置->安全性。单击“默认主体到角色映射”旁边的“启用”,然后保存即可。就是这样。 - Vineet Reynolds
@sfrj,domain.xmldomainHome/config 目录下。在管理控制台中进行的任何更改都将在此文件中反映出来。我认为问题不在连接池上,而是你指定的 JNDI 名称。在你的情况下,你创建的数据源的 JNDI 名称应该是 jdbc/security(在 domain.xml 文件中,应该在 jdbc-resourceresource-ref 标签中指定 jndi-nameref 属性)。 - Vineet Reynolds
@Vinnet Reynolds 我已经在努力解决这个问题三天了,但我觉得我快要解决了。问题有点长,可能会让人感到困惑,所以我决定接受这个问题(几乎所有的问题都已经解决了),并在以下链接开启一个新的问题来处理当前的问题:http://stackoverflow.com/questions/7994068/cannot-load-group-for-jdbc-realm - javing
@Matt Handy感谢你的评论,也很有用。我按照你所说的更改了领域中的配置以使用Join表,但仍然面临同样的问题。请参阅此链接: http://stackoverflow.com/questions/7994068/cannot-load-group-for-jdbc-realm - javing
显示剩余26条评论

3
除了Vineet的答案外,我还注意到GlassFish安全选项卡中未选中“Security Manager”选项,该选项应启用,以便在您的领域中使用安全性。
另外,如果您正在使用JDBC JNDI名称,则不需要向JDBC领域提供用户名/密码。

我勾选了“安全管理器”框,但什么也没有发生,控制台仍然显示相同的异常。关于数据库用户和密码,我认为填写这些字段不会有影响吧? - javing
另一个清晰的错误信息是:java.sql.SQLSyntaxErrorException: Schema 'ADMIN' 不存在,它是否存在?这个Schema存在吗? - Cristiano Fontes
另外一件事,你的表格没有遵循标准的JDBC规则,它们不应该有那样的映射,而且Groups表的键应该是与你用于登录的确切ID相同...你正在使用电子邮件作为登录名,但是Groups数据库的主键不是电子邮件而是ID。你可以尝试将其更改为电子邮件,看看是否可以解决问题。 - Cristiano Fontes
我已经重新启动了服务器,目前正在修复模式问题,我也注意到了这个问题。关于表格,我看不出为什么它们不能工作?你知道哪里有最佳实践的链接可以让我查看如何制作这些表格吗? - javing
JDBCrealm只是创建JDBC领域的示例,因此它不是100%可定制的。一个月前我也遇到了与你相同的问题...我认为它是使用连接在选择中使用用户的登录获取组所以其他表设置将无法工作...如果您需要另一种设置,则必须创建自己的领域,这就是我所做的。这里是一个链接,其中包含“正常”表。http://blogs.oracle.com/swchan/entry/jdbcrealm_in_glassfish_with_mysql - Cristiano Fontes

2

我已经在Sailfin上完成了这个操作(基于Glassfish 2)。

首先,我没有看到任何sun-web.xml文件将web.xml文件中定义的角色映射到数据库中定义的组。

其次,根据这篇教程:http://codepimpsdotorg.blogspot.com/2007/12/glassfish-jdbc-realm-authentication.html ,您必须指定一个摘要算法(“none”不是一个选项,在Glassfish 3中是否仍然保持不变不确定)。

第三,表和列需要按特定顺序排列,我们使用以下结构:

@Entity
@Table(name = "AuthenticationUser")
public class UserEntity implements Serializable, Identifiable
{   
    private static final long serialVersionUID = -1213555368237839900L;

    @Id
    @Column(name = "name", length = 20)
    private String itsName;

    @Column(name = "password", length = 1024)
    private String itsPassword;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "groupName", referencedColumnName = "name")
    private GroupEntity itsGroupEntity;
...

并且

@Entity
@Table(name = "AuthenticationGroup")
public class GroupEntity implements Serializable, Identifiable
{
    private static final long serialVersionUID = -1213554368237839900L;

    private static final String USER_GROUP_COLUMN = "itsGroupEntity";

    @Id
    @Column(name = "name", length = 20)
    private String itsName;

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY,
            mappedBy=USER_GROUP_COLUMN)
    private List<UserEntity> itsUsers;
...

并定义领域:

user-table=AuthenticationUser
user-name-column=name
password-column=password
group-table=AuthenticationUser
group-name-column=groupName

重要提示:用户名和组名属于同一张表!因此,认证组表(AuthenticationGroup)仅用于内部使用,不被Glassfish使用。


2
我遇到了同样的问题。 我通过将表中的密码重命名为(User_password)和用户名(User_name)字段来解决这个问题(除了用户名和密码之外,其他任何名称都可以),以某种方式使用“userName”和“password”会在使用Realms进行身份验证时导致某些冲突。 此外,如果您将密码存储为纯文本,请将Digest Algorithm:= none设置为。 在安全菜单中, 启用默认主体到角色映射。 希望这有所帮助,

有时候列的名称可能会引起冲突。这取决于数据库,很好我们解决了这个问题,这并不容易 :) - javing

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接