I have a JSF page contentEdit.xhtml which accepts a request parameter "code" to load the content for editing and other operations related. To provide access control, I create a filter ContentAccessFilter and applies it to contentEdit.xhtml to check whether the current user is authorized to the content which is identified by "code".
Fragment of ContentAccessFilter:
boolean isAuthorized = false;
String userId = httpReq.getRemoteUser();
String code = httpReq.getParameter("code");
if (code != null && !code.isEmpty())
{
ContentDAO dao = ContentDAO.getInstance();
isAuthorized = dao.isContentAuthorized(code, userId);
}
if (!isAuthorized)
{
httpRes.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
For the first entry of the contentEdit.xhtml, the filter works properly as the code parameter always exists during the first entry by calling such as /contentArea.xhtml?code=cnn from an anchor html tag. However, the code parameter is lost when there is subsequent operations on contentEdit.xhtml. For example, I have buttons like these.
<p:commandButton value="Download" action="#{contentView.downloadContent}"/>
<p:commandButton value="Publish" action="#{contentView.publishContent}"/>
Clicking the button will call the same URL as contentEdit.xhtml, while the parameter code is not included in the request URL. This missing parameter fails in the filter.
Is using a Servlet Filter a proper way to achieve the access control in this case? If it is, how to include a request parameter when triggers a commandButton?
Filters are a great way to implement authorization in a web app... you're on the right track.
The best way would be to use your filter but store the code parameter value in a session (javax.servlet.http.HttpSession), that way the parameter doesn't need to be passed in the query string with each request. You would set the code attribute in the session data on the first request and retrieve it whenever a new request is received.
If you must use the query string to pass the code value with each request, you'll need to use the includeViewParams parameter in the query string creation to preserve the code parameter in the generated URLs. BalusC (the JSF God) explains this better than anyone... https://stackoverflow.com/a/17745573/3858863
Related
I have come across what appears to be an inconsistency in MVC 5 regarding the Html.Actionlink. In different cshtml files I can use the same code, but the url target that is generated is different.
For example, this line of code:
<td>#Html.ActionLink(item.Description, "Edit", new { item.ParentTableID }) </td>
generates this URL
localhost\MyControllerClass\Edit?ParentTableID=35
That then properly calls the ActionView method Edit and feeds the parameter with 35 as expected.
However, in another cshtml file, this line
<td>#Html.ActionLink("Edit", "EditChild", new { id = f.ApplicationTableFieldID})</td>
produces this url
localhost/MyControllerClass/Edit/7
and when it hits the EditChild Action View, the parameter is null.
I have seen this now a couple of times and not yet been able to understand what makes the difference. But I need the first result.
Thanks.
Ensure that your ID parameters are named correctly in both your Action method and your ActionLink Html helper. The visual difference comes from MVC default routing and how it can take a parameter named ID and put it in the URL without the query string (? followed by stuff)
If your action method looks like this
public ActionResult EditChild(int ParentTableID){}
Then you will need to have your ID parameter named ParentTableID when you pass it back in your URL
<td>#Html.ActionLink("Edit", "EditChild", new { ParentTableID = f.ApplicationTableFieldID})</td>
Should now produce the following URL
localhost\MyControllerClass\EditChild?ParentTableID=3
I am trying to make my app "Bookmarkable", and i am using view parameters to achieve it.
And i think i still do not get the right way to do it right in JSF, even after reading this, and many others.
My problem is that the get parameters get lost after any non-ajax postback, i mean, the parameter value is still set in the bean and the app works correctly, but it gets removed from the URL making the URL invalid.
For instance, having an URL like http://company.com/users?id=4, as soon as that page executes a non-ajax postback (for uploading data, for instance) the URL becomes just http://company.com/users. The app continues to work correctly, but the link is not any more "Bookmarkable".
Is there any way to prevent the non-ajax postbacks removing the viewParams from the URL?
My use case is to be able to bookmark a page to EDIT an object, and there i need to be able to upload data (if not i would not use non-ajax postbacks). I know i would not need any postback if i would want to bookmark the page to only VIEW the data of the object, but that is not my case.
I could also do a redirect to the same page with the same params, and let the app to recreate the view scoped bean, but then i really do not see any benefit over request scoped beans...
Any suggestion is very appreciated.
This behaviour is "by design". The <h:form> generates a HTML <form> element with an action URL without any view parameters. The synchronous POST request just submits to exactly that URL which thus get reflected as-is in browser's address bar. If you intend to keep the view parameters in the URL, while using ajax is not an option, then you basically need to create a custom ViewHandler which has the getActionURL() overridden to include the view parameters. This method is used by <h:form> to generate the action URL.
public String getActionURL(FacesContext context, String viewId) {
String originalActionURL = super.getActionURL(context, viewId);
String newActionURL = includeViewParamsIfNecessary(context, originalActionURL);
return newActionURL;
}
Or, as you're based on the comments already using OmniFaces, you could also use its <o:form> component which basically extends the <h:form> with the includeViewParams attribute which works much like the same as in <h:link> and <h:button>.
<o:form includeViewParams="true">
...
</o:form>
This way all <f:viewParam> values will end up in the form action URL.
See also:
Handling view parameters in JSF after post
I need to do the thing like this (setting ActionForm attribute):
<html:form action="Link.do?method=editNews">
<html:hidden property="idNews" value="${news.newsMessage.idNews}" />
<html:submit value="EDIT"/>
</html:form>
But in <html:link> or regular a-href tag. So I don't want this parameter to apear in my link as a request parameter. Is it possible?
P.S. idNews is the parameter in my ActionForm class and it has setter and getter.
No, it's not possible. A link performs a GET request, and the only way for a GET request to send information to the server is to use request parameters, which appear in the URL.
The only thing you can do is to have your link invoke a JavaSCript function which submits a hidden form using POST. But it's ugly.
Why do you fear by making the parameter visible in the URL? Are you aware that anybody can view the source of your HTML page and see the hidden field here?
I have a situation, I have a session bean with list, this list I show in html data table. When the user hits the url from browser or normal href, I have to show all records. There is provision to search for the data also, where I have to show the filtered list. Now after a user has made the search, the list contains filtered records and after doing this he leaves the page to some other, and now if the user hits the url or uses the menu to come back to this page, since I have this list in session bean, I still have the filtered list.
Since there is no default action in JSF 1.1 or 2.0 preRenderView concept, its difficult to clear the list and get non filtered data(all results) again. Even tricks in getList() method fail to accomplish the task.
I have planned to use phase listener, as when a user reaches a page via href or url hit in browser, invoke application phase does not happen. I can toggle boolean variable in my session bean and in getList() I can perform some trick to check it was url,href hit or by command button.
Hope I have made myself clear. In short I have to identify in my bean whether the request came directly from href,browser or an action. If search action filter records for data table if not keep list cache and keep showing it as long as search is not made.
Just guide me whether I am doing things in right way or thinking too much or can it be done in much more efficient way.
Thanks in advance.
Well platform is jsf 1.1 in weblogic portal 10.3 .....
JSF 1.x actions use by default POST method. Direct links/bookmarks/etc are by nature GET method. Since there's no ResponseStateManager#isPostback() or FacesContext#isPostback() in JSF 1.1, you have to determine the request method yourself:
HttpServletRequest request = (HttpServletRequest) facesContext.getExternalContext().getRequest();
boolean postback = "POST".equalsIgnoreCase(request.getMethod());
Or check for a certain parameter in the request parameter map, but I can't tell from top of head which one you'd like to check. You've to determine it yourself.
boolean postback = facesContext.getExternalContext().getRequestParameterMap().containsKey(SOME_KEY);
If postback is true, then a JSF action is been invoked.
I'm a Java programmer, but not a JavaScript programmer. I have just discovered YUI, and am trying to get started using it. What I'd like to try and do is have the query form at the top of the page, the user press Submit and the results show up in a YUI DataTable below the query form.
Normally, of course, on a HTML form the user presses Submit, the request gets sent to the server, and I use Struts to process it and then forward the request to a JSP and HTML gets sent back to the browser. That's what I do on a daily basis. With Ajax, I understand it's different in that I should return XML instead. Not a problem. Easy to do.
The questions I have deal with the YUI side of things. When the Submit button is pressed, what happens? Not normal form submission, right? Do I implement an onSubmit() JavaScript function which then triggers some YUI DataSource to go fetch the data? How do the request params get passed? Hopefully I don't have to construct the request manually. I'm guessing that I use a YAHOO.util.XHRDataSource and that's the DataSource for the DataTable.
I've managed to get the YUI DataTable to work using an HTML table element. Now I just need to switch it over to real data. Curiously, the YUI documentation seems a bit weak here, unless I'm missing something. Maybe this is just basic Ajax that the YUI docs don't cover?
First of all, when working with Ajax you don't need to return XML from the server, you could return plain text, XML, JSON strings, literally any form of textual data that you want. One example of populating a Datatable with JSON data is provided here:
http://developer.yahoo.com/yui/examples/datatable/dt_xhrjson.html
An example of how to send a post request using Ajax and YUI is provided here.
http://developer.yahoo.com/yui/examples/connection/post.html
That should get you started, now just link both of them together.
To connect to the server you can use the Yahoo.util.Connect.asyncRequest method which takes in the following parameters:
static object asyncRequest ( method , uri , callback , postData );
See an example here, this one uses "GET" so you can use either "GET" or "POST" just make sure you pass in your parameters
http://developer.yahoo.com/yui/examples/json/json_connect.html
Once your function returns on your "onSuccess" do the following to parse the response text to JSON
try {
jsonData = YAHOO.lang.JSON.parse(o.responseText);
}
catch (x) {
alert("JSON Parse failed!");
return;
}
The "jsonData" object now contains your data, so now you can follow this example:
http://developer.yahoo.com/yui/examples/datatable/dt_basic.html
It shows you how to initialize a datatable with a local object holding the datasource. basically it would be something like this
var myColumnDefs = [
{key:"Column1Data", label:"Column1 Header" sortable:true, resizeable:true},
{key:"Column2Data", label:"Column2 Header" sortable:true, resizeable:true}
];
var myDataSource = new YAHOO.util.DataSource(jsonData);
myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSARRAY;
myDataSource.responseSchema = {
fields: ["Column1Data","Column2Data"]
};
var myDataTable = new YAHOO.widget.DataTable("basic",
myColumnDefs, myDataSource, {caption:"DataTable Caption"});
For this to work, you have to have a "div" container in the HTML code with an id of "basic" note this matches the first parameter on the DataTable
Hope this helps