I'm building a REST API with jax-rs and WildFly 10. Some of the endpoints are secured. I'm using FORM based authentication.
In my javascript code, I check the response of the AJAX
request, and if it is set to 401 Unauthorized
, I then present a login form to the user. When he fills it in, I POST the details to j_security_check
.
Running on localhost
this all works fine, but when the webserver and the REST server are on different machines, the browser denies the AJAX request due to cross-origin issues.
I understand CORS, so I added a CORS filter to my REST server that sets CORS headers for the GUI server. It all works fine, except for one small, but important detail: after the login has succeeded, the CORS filter does not fire for the j_security_check
response. No CORS headers are added and the browser can not read the response.
Apart from this one detail I have the whole setup working exactly like I want it.... But I have been struggling with this detail all night and I just can't get it to work.
I understand there are issues with trying to filter j_security_check
, but I know of no other ways to add CORS headers... So my question is:
How do I add CORS headers to the response for j_security_check
?
Configuring undertow
subsystem in standalone.xml
/domain.xml
file solved this problem for me. Filters configured there handle all the requests including j_security_check
one.
<subsystem xmlns="urn:jboss:domain:undertow:3.0">
<buffer-cache name="default"/>
<server name="default-server">
<http-listener name="default" redirect-socket="https" socket-binding="http"/>
<host name="default-host" alias="localhost">
<location name="/" handler="welcome-content"/>
<filter-ref name="server-header"/>
<filter-ref name="x-powered-by-header"/>
<!--CORS headers -->
<filter-ref name="Access-Control-Allow-Origin"/>
<filter-ref name="Access-Control-Allow-Methods"/>
<filter-ref name="Access-Control-Allow-Headers"/>
<filter-ref name="Access-Control-Allow-Credentials"/>
<filter-ref name="Access-Control-Max-Age"/>
</host>
</server>
<servlet-container name="default">
<jsp-config/>
<websockets/>
</servlet-container>
<handlers>
<file name="welcome-content" path="${jboss.home.dir}/welcome-content"/>
</handlers>
<filters>
<response-header name="server-header" header-value="WildFly/10" header-name="Server"/>
<response-header name="x-powered-by-header" header-value="Undertow/1" header-name="X-Powered-By"/>
<!-- CORS headers -->
<response-header name="Access-Control-Allow-Origin" header-name="Access-Control-Allow-Origin" header-value="*"/>
<response-header name="Access-Control-Allow-Methods" header-name="Access-Control-Allow-Methods" header-value="OPTIONS, GET, POST, PUT, DELETE"/>
<response-header name="Access-Control-Allow-Headers" header-name="Access-Control-Allow-Headers" header-value="accept, authorization, content-type, x-requested-with"/>
<response-header name="Access-Control-Allow-Credentials" header-name="Access-Control-Allow-Credentials" header-value="true"/>
<response-header name="Access-Control-Max-Age" header-name="Access-Control-Max-Age" header-value="60"/>
</filters>
</subsystem>
Of course you'd better replace "*"
wildcard by your GUI server's url in the Access-Control-Allow-Origin
header's value attribute.
Handle the login yourself.
Instead of posting to j_security_check
, post to /auth/login
or something like that and handle the login. Something like this:
@POST
@Path("login")
@PermitAll
public Response postLogin() {
String user = request.getParameter("j_username");
String password = request.getParameter("j_password");
StringBuffer buf = request.getRequestURL();
URI redir = null;
try {redir = new URI(buf.substring(0, buf.lastIndexOf("/login")) + "/session");}
catch (URISyntaxException e) {}
try {
request.login(user, password);
return Response.seeOther(redir).build();
} catch (ServletException e) {
if (e.getMessage() != null && e.getMessage().equals("UT010030: User already logged in")) {
Response.seeOther(redir).build();
}
return Response.status(Status.FORBIDDEN).build();
}
}
Based on nfedorov's answer, I came to the conclusion that he is right and that an Undertow filter is the only type of filter that can operate on container responses. So if we want to add CORS headers to these responses, we need an Undertow filter. So I wrote one:
undertow-cors-filter
Download the .zip file and unzip it in your Wildfly root folder. Then add a filter
configuration to standalone.xml
:
<filters>
<filter name="undertow-cors-filter" class-name="com.stijndewitt.undertow.cors.Filter" module="com.stijndewitt.undertow.cors">
</filter>
</filters>
Add a filter-ref
to the host
element (still in standalone.xml
):
<host name="default-host" alias="localhost">
<filter-ref name="undertow-cors-filter" />
</host>
This will add CORS headers allowing all origins access to all responses this server emits.
Add param
s to the filter
definition to configure the behavior. For example, if you want the filter to apply only to responses for requests to URLS starting with /api
and you only want to allow example.com and example.org access, you could use a configuration similar to this:
<filters>
<filter name="undertow-cors-filter" class-name="com.stijndewitt.undertow.cors.Filter" module="com.stijndewitt.undertow.cors">
<param name="urlPattern" value="^http(s)?://([^/]+)(:([^/]+))?(/([^/])+)?/api(/.*)?$" />
<param name="policyClass" value="com.stijndewitt.undertow.cors.AllowMatching" />
<param name="policyParam" value="^http(s)?://(www\.)?example\.(com|org)$" />
</filter>
</filters>
There are 3 policy classes available, AllowAll
, AllowMatching
and Whitelist
and you can write your own custom policies if needed.
来源:https://stackoverflow.com/questions/35217936/add-cors-headers-to-response-of-j-security-check