我理解整个过程如何运作,但是有些问题出现了,我无法使其正常工作。
首先我创建了一个带有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...
}
当数据库准备好后,我手动添加了一些数据。 下一步是配置安全域。
然后将安全配置添加到我的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标签?
我真的很感激一些帮助,我已经花费了几个小时阅读书籍的前几章并尝试实现自己的示例,但我卡住了。 我认为我接近解决方案。
更新
我将默认主体更改为访客用户名。 但仍然无法正常工作。
我还向我的Realm配置中添加了一些选项。
但是当我尝试登录时,仍然看到一个异常,内容如下:
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
也许连接池出了问题。 这是我的连接池的样子:
我没有太多属性,可能有些东西缺失了吗?
现在我创建了一个JDBC资源,看起来像这样:
领域中的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,现在它看起来像这样:
但是当我登录时,我再次遇到了异常: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