实现用户登录表单, 接收用户登录信息,对用户提交的用户名和密码进行验证(Jakarta Security 实验)
实验目的: 掌握对用户进行身份验证和访问控制的方法;
第一步:配置表单认证机制
在 RestApplication 中,我们需要使用 @FormAuthenticationMechanismDefinition 注解来配置表单认证机制。通过设置 loginPage 和 errorPage,我们指定了用户登录和登录失败时的页面。该配置确保系统在用户访问受保护资源时,如果未登录,自动重定向到登录页面。
@FormAuthenticationMechanismDefinition(loginToContinue = @LoginToContinue(loginPage = "/login.html", // 登录页面路径 errorPage = "/login-error.html" // 登录失败页面路径 ))@ApplicationPath("/api") // 定义API路径public class RestApplication extends Application {}
解释:
- loginPage:用户访问需要身份验证的资源时,如果尚未登录,系统将自动跳转到此登录页面。
- errorPage:如果用户登录失败,系统将跳转到此错误页面。
第二步:创建登录表单
我们需要创建一个登录页面 login.html,该页面将通过 POST 请求提交用户名和密码。表单提交的路径为 j_security_check,这是 Jakarta Security 所规定的默认路径。
login.html 示例:
<form method="POST" action="j_security_check">登录名: <input type="text" name="j_username"><p>密码: <input type="password" name="j_password"><p><input type="submit" value="登录"></form>
解释:
- j_username 和 j_password:这两个字段是表单认证机制默认使用的字段名,代表用户的用户名和密码。
- j_security_check:这是表单提交的路径。Jakarta Security 会使用这个路径来处理用户登录认证。
第三步:配置 Jakarta Security 身份验证
在 RestApplication 类中,我们需要配置数据库身份验证。通过 @DatabaseIdentityStoreDefinition 注解,定义如何从数据库中获取用户的用户名、密码和角色信息。这里我们配置了 callerQuery 来查询用户名对应的密码,groupsQuery 来查询用户所属的角色。
配置示例:
@DatabaseIdentityStoreDefinition(dataSourceLookup = "jdbc/myDB", // 数据源名称 callerQuery = "select UsrPwd from Usr where UsrName = ?", // 查询用户密码 groupsQuery = "select grpName from UsrGrp where UsrId = ?", // 查询用户角色 hashAlgorithm = Pbkdf2PasswordHash.class, // 密码加密算法 hashAlgorithmParameters = {"Pbkdf2PasswordHash.Iterations=3072","Pbkdf2PasswordHash.Algorithm=PBKDF2WithHmacSHA512","Pbkdf2PasswordHash.SaltSizeBytes=64"},priority = 30)
解释:
- dataSourceLookup:指定数据库的数据源,系统会从此数据源中查询用户和角色信息。
- callerQuery:SQL 查询,获取用户密码。
- groupsQuery:SQL 查询,获取用户角色。
- hashAlgorithm:指定密码的哈希算法,这里使用的是 PBKDF2。
- priority:优先级,数字越小,优先级越高。
第四步:定义应用的角色和安全约束
在 RestApplication 类中,使用 @DeclareRoles 注解声明应用支持的角色。角色可以是多个,例如 admin 和 user。然后,定义安全约束,指定哪些角色有权访问哪些资源。
配置示例:
@DeclareRoles({ "admin", "user" }) // 声明支持的角色 @ApplicationPath("/api") // 定义API路径public class RestApplication extends Application {}
解释:
- @DeclareRoles:声明应用支持的角色。这里我们声明了两个角色 admin 和 user。
- @ApplicationPath:定义应用的基础路径。这里指定 /api 作为API路径。
第五步:定义受保护资源
我们需要定义一些受保护的资源并使用 @RolesAllowed 注解来控制哪些角色可以访问这些资源。在这个示例中,我们定义了一个 UserResource 类,分别为 user 和 admin 用户角色设置了访问权限。
UserResource 示例:
@Path("/user")public class UserResource {@GET@RolesAllowed("user")public String getUserInfo() {return "This is a user-specific resource.";}@GET@RolesAllowed("admin")public String getAdminInfo() {return "This is an admin-specific resource.";}}
解释:
- @RolesAllowed("user"):只有角色为 user 的用户才能访问该方法。
- @RolesAllowed("admin"):只有角色为 admin 的用户才能访问该方法。
第六步:测试
完成上述配置后,我们可以进行测试:
- 访问受保护资源:如果未登录,系统会自动跳转到 /login.html。
- 提交登录表单:用户输入用户名和密码后提交表单。
- 验证用户角色:如果登录成功,根据用户角色(user 或 admin)返回不同的资源内容。
- 自动重定向:用户成功登录后,如果之前尝试访问的是受保护资源,系统将自动跳转回该资源。
测试场景:
- 用户访问 /api/user,系统会提示登录。
- 用户登录后,如果角色是 user,访问 /api/user 会返回 "This is a user-specific resource."。
- 如果角色是 admin,访问 /api/user 会返回 "This is an admin-specific resource."。
总结
在这个实验中,我们通过配置表单认证、数据库身份验证、角色声明和资源保护,成功实现了一个简单的身份验证系统。用户登录后,系统根据用户角色返回不同的资源。这个实验帮助我们掌握了如何在 Jakarta EE 中实现基于角色的访问控制和安全机制。