我正在调查使用wildfly自定义登录模块的可行性。
客户端会将移动设备ID作为登录的一部分传递给服务器。我将以通常的方式检查用户名和密码是否正确,然后我需要检查移动设备是否被批准使用该服务。
我的想法是,我将有一个调用HttpServletRequest.login(u,p)的restful webservice方法登录。
如何在HttpServletRequest中获取登录模块中的移动设备ID?
我可以登录,如果成功,则测试webservice中的设备ID,如果未经批准,请将用户注销。但这似乎相当混乱。
这样做的正确方法是什么?
修改
反馈:我按照克里斯建议的方式做到了。我实现了自己的CallBackHandler版本和Callback接口的实现,在我的登录模块的登录方法中,我执行以下操作:
public boolean login() throws LoginException {
boolean login = super.login();
if (login) {
UuidCallback uuidCallback = new UuidCallback();
try {
super.callbackHandler.handle(new Callback[]{uuidCallback});
} catch (Exception e) {
LoginException le = new LoginException("Failed to get uuid");
le.initCause(e);
throw le;
}
System.out.print("Device UUID: "+uuidCallback.getUuid());
}
return login;
}
在Web服务登录方法中:
@Path("/login")
@Produces({ "application/json" })
public class LoginWebService {
@POST
public Response login(@Context HttpServletRequest request) throws LoginException {
CallbackHandler callbackHandler = new MyCallbackHandler(request.getParameter("username"), request.getParameter("password"), request.getParameter("uuid"));
Subject subject = new Subject();
LoginContext loginContext = new LoginContext("securityDomain", new subject, callbackHandler);
loginContext.login();
MyPrincipal principal = subject.getPrincipals(MyPrincipal.class).iterator().next();
}
}
您也可以在回调处理程序上设置uuid,然后在getUUID()
方法内的回调处理程序上调用LoginModule.login
。但我选择了设计,即使它对我来说没有意义。
登录时我仍然收到403并尝试访问受保护资源,如果auth-constraint/role-name
为*,则必须提供至少一个security-role
。
<login-config>
<auth-method>FORM</auth-method>
<realm-name>mydomain</realm-name>
</login-config>
<security-constraint>
<web-resource-collection>
<web-resource-name>rest</web-resource-name>
<url-pattern>/rest/app/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>*</role-name>
</auth-constraint>
</security-constraint>
<!-- after login there is a 403 on protected resources if no role and role-name * -->
<security-role>
<role-name>user</role-name>
</security-role>
我的所有用户都有一个角色用户,可以让他们访问。我能够通过排除security-role
来使其工作,但是auth-constraint/role-name
必须设置为文字角色,在我的情况下:“user”
答案 0 :(得分:0)
您可以直接从Restful Web服务调用 HttpServletRequest.login()方法,而不是在Wildfly中配置安全域。
此安全域应在您的webapp web.xml 文件login-config元素中引用,并带有安全约束,以启用JAAS
以下是web.xml file声明安全约束和login-config(使用BASIC身份验证方法)的示例
使用标准提供的数据库登录模块而非自定义数据库登录模块的安全域配置的Wildfly standalone.xml 配置示例:
<security-domain name="securityDomain" cache-type="default">
<authentication>
<login-module code="Database" flag="required">
<module-option name="dsJndiName" value="java:/TestDS"/>
<module-option name="principalsQuery" value="select password from User where login = ? and (disabled is null or disabled = 0) and activated = 1"/>
<module-option name="rolesQuery" value="select name,'Roles' from Role r, User_Role ur, User u where u.login=? and u.id = ur.userId and r.id = ur.roleId"/>
<module-option name="hashAlgorithm" value="SHA-256"/>
<module-option name="hashEncoding" value="base64"/>
<module-option name="unauthenticatedIdentity" value="guest"/>
</login-module>
</authentication>
</security-domain>
然后,在您的REST资源中,您只需使用@RolesAllowed或@PermitAll注释来限制访问权限或不执行授权。
答案 1 :(得分:0)
我建议创建一个LoginContext并通过CallbackHandler的实现传递。在callbackhandler中为额外的UUID属性提供支持。
虽然此代码适用于我,但您需要更新它以满足额外的UUID属性
public class NamePasswordCallbackHandler implements CallbackHandler {
private final String username;
private final String password;
private NamePasswordCallbackHandler(String username, String password) {
this.username = username;
this.password = password;
}
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
for (Callback current : callbacks) {
if (current instanceof NameCallback) {
((NameCallback) current).setName(username);
} else if (current instanceof PasswordCallback) {
((PasswordCallback) current).setPassword(password.toCharArray());
} else {
throw new UnsupportedCallbackException(current);
}
}
}
}
我创建了自己的Configuration对象实现(如下所示为JBossJaasConfiguration)。
然后通过这个callbackhandler传递给你的LoginContext:
CallbackHandler cbh = new NamePasswordCallbackHandler(username, password);
Configuration config = new JBossJaasConfiguration("mysqldomain");
LoginContext loginContext = new LoginContext("mycontext", new Subject(), cbh, config);
loginContext.login();
属性“mysqldomain”与standalone.xml中的安全域名称相关
<subsystem xmlns="urn:jboss:domain:security:1.2">
<security-domains>
<security-domain name="mysqldomain" cache-type="default">
<authentication>
<login-module code="com.soccerx.security.DatabaseServerLoginRealm" flag="required">
<module-option name="dsJndiName" value="java:jboss/datasources/SoccerSoftwareDS"/>
<module-option name="principalsQuery" value="select userId, tenantId, password, salt from User where username=? and StatusId != 2"/>
<module-option name="rolesQuery" value="select Role, 'Roles' from User where Username=?"/>
<module-option name="password-stacking" value="useFirstPass"/>
<module-option name="principalClass" value="com.soccerx.security.DatabasePrincipal"/>
</login-module>
</authentication>
</security-domain>
<security-domains>
</subsystem>
虽然这不是满足您需求的完整解决方案,但我希望您可以修改它以确保在UUID不匹配时登录失败。
注意:您需要在CustomDatabaseLoginRealm中满足此要求,如standalone.xml中所定义。含义访问用户名/密码/ uuid并将其与数据库中的值进行比较。
更多文档请参阅here