如何在Arquillian功能测试中创建Payara用户账户?
@RolesAllowed保护的REST接口方案 你好,针对你目前在嵌入式Payara(4.1.2.174)上用Arquillian+Graphene测试带@RolesAllowed注解的REST接口认证功能的困境,我整理了几个无需切换到远程实例的可行方案:
方案1:通过Payara嵌入式编程API直接创建用户/角色
嵌入式Payara其实暴露了内部管理API,你可以在测试启动阶段通过编程方式操作安全域,添加测试用户和角色。步骤如下:
- 确保依赖正确:在你的测试构建脚本(比如Maven的pom.xml)中引入Payara嵌入式全量依赖,版本对应4.1.2.174,scope设为
test:
<dependency> <groupId>fish.payara.extras</groupId> <artifactId>payara-embedded-all</artifactId> <version>4.1.2.174</version> <scope>test</scope> </dependency>
- 编写测试前置逻辑:在测试类中添加
@BeforeClass注解的方法,或者结合Arquillian的部署钩子,获取嵌入式容器的内部实例来操作安全域:
import org.glassfish.api.admin.ServerEnvironment; import org.glassfish.internal.api.Globals; import com.sun.enterprise.security.auth.realm.Realm; import com.sun.enterprise.security.auth.realm.file.FileRealm; @BeforeClass public static void setupTestUsers() throws Exception { // 获取Payara默认的文件型安全域 Realm realm = Realm.getInstance("file"); if (realm instanceof FileRealm) { FileRealm fileRealm = (FileRealm) realm; // 添加测试用户:用户名、加密前密码、关联角色数组 fileRealm.addUser("testAdmin", "adminPass".toCharArray(), new String[]{"ADMIN"}); fileRealm.addUser("testUser", "userPass".toCharArray(), new String[]{"USER"}); } }
注意:如果默认的file安全域不符合你的测试需求,也可以通过API创建自定义安全域,不过大部分场景下默认域足够覆盖认证测试。
方案2:在WAR包中嵌入预配置的安全域数据
你可以把用户、角色的预配置文件打包到WAR中,配合glassfish-web.xml(或payara-web.xml)指定安全域路径,让嵌入式Payara启动时自动加载这些数据:
生成用户数据文件:
- 先通过本地Payara的
asadmin命令生成加密后的用户密码:asadmin create-file-user --userpassword yourPass testUser,然后复制输出的加密字符串 - 在项目资源目录创建
users.properties:testUser={SSHA}xxxxxxxxx(替换成刚才生成的加密密码) - 创建
groups.properties:testUser=USER,ADMIN
- 先通过本地Payara的
配置安全域映射:在
WEB-INF/glassfish-web.xml中添加配置,指定安全域和数据文件路径:
<glassfish-web-app> <security-role-mapping> <role-name>ADMIN</role-name> <group-name>ADMIN</group-name> </security-role-mapping> <security-role-mapping> <role-name>USER</role-name> <group-name>USER</group-name> </security-role-mapping> <realm>file</realm> <property name="fileRealm.users" value="${com.sun.aas.instanceRoot}/config/users.properties"/> <property name="fileRealm.groups" value="${com.sun.aas.instanceRoot}/config/groups.properties"/> </glassfish-web-app>
- 打包到部署包:在Arquillian的
@Deployment方法中,把配置文件添加到WAR的对应路径:
@Deployment public static WebArchive createDeployment() { return ShrinkWrap.create(WebArchive.class) // 添加你的应用类、REST接口等资源 .addAsResource("users.properties", "config/users.properties") .addAsResource("groups.properties", "config/groups.properties") .addAsWebInfResource("glassfish-web.xml"); }
方案3:利用Arquillian容器配置传递启动命令
你可以在arquillian.xml中配置嵌入式Payara的启动参数,模拟执行asadmin创建用户的命令——虽然嵌入式模式没有独立的asadmin进程,但Payara支持通过启动参数直接执行管理命令:
<container qualifier="payara-embedded" default="true"> <configuration> <property name="glassFishHome">${payara.embedded.home}</property> <property name="asadminCommands"> create-file-user --userpassword adminPass --groups ADMIN testAdmin; create-file-user --userpassword userPass --groups USER testUser; </property> </configuration> </container>
注意:这个方案依赖Payara嵌入式容器的实现细节,你可以针对4.1.2.174版本测试是否生效,如果参数格式不兼容,可调整命令的写法。
关于旧方案失效的说明
你提到的早期方案(比如注入CommandRunner)失效,是因为Payara 4.x对GlassFish的管理API做了重构,CommandRunner的包路径和调用逻辑都发生了变化;而找不到对应的Server类,是因为嵌入式Payara的类路径中没有暴露该公开API,需要直接使用内部的GlassFish/Payara类(比如方案1中的Realm相关实现)。
内容的提问来源于stack exchange,提问作者Kalle Richter

