help me
index.jsp
$("#btn-submit").click(function () {
var username=document.getElementById("username");
var password=document.getElementById("password");
$.ajax({
url:"login",
contentType: 'application/json;charset=utf-8',
dataType: 'text',
headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')},
data: {
username:username.value,
password:password.value
},
type: 'get',
success: function (response) {
if (response=="1") {
alert(response);
}
else alert(response);
},
error: function (x, e) {
console.log(e)
}
});
});
LoginController.java
#RequestMapping("/login")
#Controller
public class LoginController {
#Autowired
private UserService userService;
#RequestMapping(value = { "/login" }, method = RequestMethod.GET)
#ResponseBody
public int checkValid(#RequestParam("username") String username,#RequestParam("password") String password, HttpServletRequest request, HttpServletResponse response, Locale locale, Model model){
try {
if (userService.findByUserName(username).equals(hashPass(password))){
return 1;
}
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return 0;
}
return 0;
}
public String hashPass(String pass) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] hashInBytes = md.digest(pass.getBytes(StandardCharsets.UTF_8));
// bytes to hex
StringBuilder sb = new StringBuilder();
for (byte b : hashInBytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
}
spring-config-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
/WEB-INF/pages/
.jsp
/resources/jdbc.properties
<!-- Enable Annotation based Declarative Transaction Management -->
<tx:annotation-driven proxy-target-class="true"
transaction-manager="transactionManager" />
<!-- Creating TransactionManager Bean, since JDBC we are creating of type
DataSourceTransactionManager -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="postsDAO" class="com.blog.dao.impl.PostsDAO">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<bean id="postsService" class="com.blog.service.impl.PostsService">
<property name="postsDAO" ref="postsDAO"/>
</bean>
<bean id="userDAO" class="com.blog.dao.impl.UserDAO">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<bean id="userService" class="com.blog.service.impl.UserService">
<property name="userDAO" ref="userDAO"/>
</bean>
I use tomcat 9
Error:Failed to load resource: the server responded http://localhost:8080/Blog_war_exploded/login?username=root&password=root with a status of 404 ()
Look at your error: You are accessing http://localhost:8080/Blog_war_exploded/login but you actually want to access http://localhost:8080/login.
The reason is that you specified your URL as login instead of /login, so it is relative to the current "directory" and not to the root.
Changing the code to use /login should fix it:
$.ajax({
url: "/login",
...
})
On a side note, it's not a good idea to this via GET requests - among other things, the password will be stored in the server log in clear text. You should use a POST request instead.
Update:
Also, it seems you are use two request mappings for /login on top of each other, so you'll end up with /login/login. Check out how to use #RequestMapping properly.
Try changing the second (method-level) one to #RequestMapping(value = { "/" }, method = RequestMethod.GET) or just #RequestMapping("/").
I think the issue is related to your RequestMapping definition on both controller level and method level.
the first login at the controller level, means if you want to access any services in this controller, your requests have to start with "/login"
#RequestMapping("/login")
#Controller
public class LoginController {
and the second login at the method level, means you want to call the /login service under /login.
#RequestMapping(value = { "/login" }, method = RequestMethod.GET)
#ResponseBody
public int checkValid(#RequestParam("username") String username,#RequestParam("password") String password, HttpServletRequest request, HttpServletResponse response, Locale locale, Model model){
So the valid URL to call the /login service under /login controller is: /login/login
and because of this, your url /login was not found
you can either remove the first /login at the controller level, or use the /login/login from your ajax request...
Related
I have implemented Spring Security in my application. Whenever someone tries to access any url if authentication is required for these urls user will be redirected to login page. Now, if AJAX call is made for any such url I would like to return JSON response instead of login page's HTML as AJAX response. How can I do that ?
You have to create json for this i am doing here with .net
var url="url";
$.ajax({
type: "get",
dataType: "json",
data:url,
async: true,
url: "testCall",//this can be your api or any server side call
success: function (data) {
},
failure: function () {
alert(textStatus);
}
});
//here is server side code for creating json
[WebMethod(EnableSession = true)]
[ScriptMethod(UseHttpGet = true)]
public void testCall(string url)
{
Context.Response.Write()//here your will just hard code the json data
//it will receive by ajax success method.
}
Faced the same thing not long ago, came out with this solution.
You'll have to redefine the authentication entry point to handle the exception and returning a proper JSON response.
First create a class for your response. Needs to be a POJO.
public class MyErrorResponse {
// your stuff here, and getters / setters
}
Then go define the authentication entry point
public class MyBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {
private List<HttpMessageConverter<Object>> messageConverters = new ArrayList<>();
private MediaType retrieveRequestMediaType(HttpServletRequest request) {
String accept = request.getHeader("accept");
if(Strings.isNullOrEmpty(accept))
accept = MediaType.APPLICATION_JSON_VALUE;
MediaType requestMediaType = MediaType.valueOf(accept);
return requestMediaType;
}
private HttpMessageConverter<Object> retrieveMessageConverter(List<HttpMessageConverter<Object>> messageConverters, Class<?> clazz, MediaType mediaType) {
for (HttpMessageConverter<Object> httpMessageConverter : messageConverters) {
if(httpMessageConverter.canWrite(clazz, mediaType)) {
return httpMessageConverter;
}
}
}
#Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
log.warn(String.format("Unauthorized access with session id '%s'", request.getSession().getId()));
MyErrorResponse esponse = new MyErrorResponse();
// populate your response object with all the info you need
MediaType mediaType = MediaType.APPLICATION_JSON;
try{
mediaType = retrieveRequestMediaType(request);
} catch(InvalidMediaTypeException imte) {
// log, do nothing
}
// getting the best fitting message converter, according to the "accept" header of the request
HttpMessageConverter<Object> httpMessageConverter = retrieveMessageConverter(messageConverters, MyErrorResponse.class, mediaType);
if(httpMessageConverter == null) {
log.info("Could not find specific handler. Using JSON.");
httpMessageConverter = retrieveMessageConverter(messageConverters, MyErrorResponse.class, MediaType.APPLICATION_JSON);
}
response.setStatus(HttpStatus.UNAUTHORIZED.value());
ServletServerHttpResponse serverHttpResponse = new ServletServerHttpResponse(errorResponse);
httpMessageConverter.write(response, mediaType, serverHttpResponse);
}
}
Once you got your bean set up, time to wire it up in the security context:
<beans:bean class="[fully qualified name of the entry point class]" id="myBasicAuthenticationEntryPoint">
<beans:property name="messageConverters">
<beans:list>
<!-- add message converters here -->
<!-- Spring provide lots of them, google it -->
</beans:list>
</beans:property>
</beans:bean>
<http use-expressions="true">
<http-basic entry-point-ref="myBasicAuthenticationEntryPoint" />
<!-- add other stuff here, if needed -->
</http>
Hope it helps
ViewResolver (my jsp is in the right folder as specified on prefix value):
<!-- Resolves views selected for rendering by #Controllers -->
<!-- to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
Servlet mapping:
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>*.fst</url-pattern>
</servlet-mapping>
Controller:
#Controller
public class HomeController {
private static final Logger logger =
LoggerFactory.getLogger(HomeController.class);
#RequestMapping("/home")
public ModelAndView home(String user, HttpServletRequest request) {
logger.info("Home controller has been executed");
ModelAndView mv = new ModelAndView();
mv.addObject("userName", user);
mv.addObject("controllerName", request.getRequestURI());
mv.setViewName("home");
return mv;
}
#RequestMapping(value = "/testAjax", method = RequestMethod.POST)
public String testAjax(#RequestParam("memberId") String id,
HttpServletRequest request, HttpServletResponse response,
Locale locale, Model model) {
logger.info("Text Ajax action has been executed. My Parameter is " + id);
return id;
}
}
After turning on Tomcat 8 server on STS IDE, accessing this web with this url http://localhost:8080/home.fst works okay.
But on the page, calling AJAX like below throws a 404 error:
$.ajax({
type: "POST",
url: "/testAjax.fst",
data: {"memberId" : "test"},
success: function (result) {
console.log(result)
}
});
This is console error log:
POST http://localhost:8080/testAjax.fst 404 (Not Found)
k.cors.a.crossDomain.send jquery-2.1.3.min.js:4
n.extend.ajaxhome.fst:11 (anonymous function) jquery-2.1.3.min.js:3
n.event.dispatch jquery-2.1.3.min.js:3
r.handle
Strange thing is that it calls testAjax controller just fine and there's no error log on server.
logger.info("Text Ajax action has been executed. My Parameter is " + id);
When textAjax action is invoked by my AJAX, the log is printed as well. I checked it out with debug point too (it broke alright).
What seems to be the matter??
Everything's good just Add #ResponseBody annotation in your method and also I suggest you to change your request method POST to GET
Spring
#RequestMapping(value = "/testAjax", method = RequestMethod.GET) //Made Change
#ResponseBody //added
public String testAjax(#RequestParam("memberId") String id, HttpServletRequest request, HttpServletResponse response, Locale locale, Model model) {
logger.info("Text Ajax action has been executed. My Parameter is " + id);
return id;
}
JQuery
$.ajax({
type: "GET", //Made Change
url:"/testAjax.fst",
data: {"memberId" : "test"},
success: function (result) {
console.log(result)
}
});
Currently I am on a legacy project of Spring mvc and annotations are not working on it.
I have to create an controller-action which will respond to an ajax call with JSON response.
I have created my controller by implementing Controller interface.
I am able to implement a jsp page with this but unable to tweek it for ajax call.
Taking help from link1 link2 link3
Xml configuration in action-servlet.xml
<bean id="jsonResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver">
<property name="order"><value>1</value></property>
</bean>
<bean name="jsonView" class="org.springframework.web.servlet.view.json.JsonView">
<property name="contentType">
<value>text/html</value>
</property>
</bean>
<bean id="myOwnController" class="com.myapp.webapp.action.MyOwnController" />
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="interceptors">
<list>
<!-- list of inteceptor urls -->
</list>
</property>
<property name="mappings">
<props>
<prop key="/mytest">myOwnController</prop>
<!-- mapping for other controller actions -->
</props>
</property>
</bean>
Controller class
package com.myapp.webapp.action
public class myOwnController implements org.springframework.web.servlet.mvc.Controller
{
#Override
public ModelAndView handleRequest(HttpServletRequest request,HttpServletResponse response) throws Exception
{
Map<String, Object> model = new HashMap<String, Object>();
model.put("success", "true");
return new ModelAndView("jsonView", model);
}
}
ajax call js method (in Prototype.js)
function myAjaxMethod(){
new Ajax.Request('${pageContext.request.contextPath}/jsonView', {
method:'get',
onSuccess: function(transport) {
var response = transport.responseText || "no response text";
alert("Success! \n\n" + response);
},
onFailure: function() { alert('Something went wrong...'); }
});
}
Also I am unable to understand that how the url in ajax call will get to know the this is the controller that should be called.Do I am missing any mapping?
Please help.
Here is an example for, how to call a spring MVC controller from ajax function
This is all done using annotation driven environment.
1) Need to make application annotation driven first and give your controller package there.
2) Add #RequestMapping to the fn that is going to be called from ajax fn, and provide maping URL to ajax fn 'url' attribute.
changes in p[om.xml
need to add, following library to convert and send response to ajax success in form of json.
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
changes in spring conf file
<context:component-scan base-package="com.beingjavaguys.controller" />
<mvc:annotation-driven />
controller code:
#RequestMapping(value = "/save", method = RequestMethod.POST, headers = { "Content-type=application/json" })
public #ResponseBody
Response saveData(#RequestBody Employee employee) {
System.out.println("First Name: " + employee.getFirstName());
System.out.println("Last Name: " + employee.getLastName());
System.out.println("Email: " + employee.getEmail());
System.out.println("Phone: " + employee.getPhone());
return new Response("1", "Done");
}
ajax function syntax
function doAjaxPost() {
var formData = JSON.stringify({
firstName : $('#firstName').val(),
lastName : $('#lastName').val(),
email : $('#email').val(),
phone : $('#phone').val()
});
$.ajax({
type : "POST",
url : "save",
data : formData,
contentType : 'application/json',
success : function(data) {
if (data.status == '1')
$('#status').html('Form data sent !');
else
$('#status').html('Error in sending data !');
}
});
}
Hope this helps.
Use a button instead of submit to prevent page load on submit form and call ajax fn onClick.
Finally I got a solution(not via Spring but via a dirty logic).
Warning : Never work on old Spring version project.
Solution : I rendered whole html response in ajax call, filter my data and parse into json.
action-servlet.xml
<bean id="myOwnController" class="com.myapp.webapp.action.MyOwnController" />
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="interceptors">
<list>
<!-- list of inteceptor urls -->
</list>
</property>
<property name="mappings">
<props>
<prop key="/mytest.html">myOwnController</prop>
<!-- mapping for other controller actions -->
</props>
</property>
</bean>
Controller class
package com.myapp.webapp.action
public class myOwnController implement org.springframework.web.servlet.mvc.Controller
{
#Override
public ModelAndView handleRequest(HttpServletRequest request,HttpServletResponse response) throws Exception
{
Map<String, Object> model = new HashMap<String, Object>();
model.put("name", "davy jones");
return new ModelAndView("mytest", model);
}
}
Calling jsp Ajax call
function createFreshdeskUser(){
new Ajax.Request('${pageContext.request.contextPath}/mytest.html', {
method:'get',
onSuccess: function(transport) {
var divIdWordLength=16;
var htmlData=transport.responseText;
var startIndex=htmlData.indexOf("<div id=\"mydiv\">");
var endHtmlData=htmlData.substring(startIndex+divIdWordLength , htmlData.length);
var endIndex=endHtmlData.indexOf("</div>");
var finalHtmlData=endHtmlData.substring(0,endIndex);
var jsonObj=eval ("(" + finalHtmlData + ")");
alert(jsonObj.name);
},
onFailure: function() { alert('Something went wrong...'); }
});
}
mytest.jsp
<head>
</head>
<body>
<div id="mydiv">{'name':'${name}'}</div>
</body>
</html>
I am setting 'cat=1' in the hidden field in login.jsp page and was expecting it to be available on the default-target-url. Entry in spring-security.xml is,
<form-login login-page="/login.html" default-target-url="/index.html"
authentication-failure-url="/loginfailed.html" />
and in the controller,
#RequestMapping(value="/index", method = RequestMethod.GET)
public String index(HttpServletRequest request) {
String cat = request.getParameter("cat");
if (cat != null && cat.equalsIgnoreCase("1")) {
return "add";
}
return "redirect:/index.jsp";
}
but cant get request parameter value (cat is null) so I believe it is because 'default-target-url' redirects the request (and does not forward it?). Is it the case?
If yes then is there any way I can pass parameter to the 'default-target-url'?
I have changed implementation approach a bit. Details give below,
spring-security.xml
<form-login login-page="/login.html" authentication-success-handler-ref="feedSuccessHandler"
authentication-failure-url="/loginfailed.html" />
<logout logout-success-url="/loggedout.html"/>
<beans:bean id="feedSuccessHandler"
class="main.java.com.sp.utilities.FeedSuccessHandler">
</beans:bean>
FeedSuccessHandler.java
public class FeedSuccessHandler implements AuthenticationSuccessHandler {
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
String cat = request.getParameter("cat");
if (cat != null && cat.equalsIgnoreCase("1")) {
response.sendRedirect(request.getContextPath()+"/add.html");
}else{
SavedRequest savedRequest = new HttpSessionRequestCache().getRequest(request, response);
if(savedRequest != null) {
response.sendRedirect(savedRequest.getRedirectUrl());
}else{
response.sendRedirect(request.getContextPath()+"/");
}
}
}
}
Application is working as desired also in future if I want to customize redirection based on roles, I can use same class.
It does redirect by defult, but there are a couple configuration options you can use to change this behavior. Both of them is defined on the AbstractAuthenticationTargetUrlRequestHandler which is the parent class of the two existing authentication success handler implementations (by default SavedRequestAwareAuthenticationSuccessHandler is used by the namespace configuration).
Set its targetUrlParameter property, so that it will check if the HTTP request has a parameter with that name. If so, it will redirect to the URL given in that request parameter.
Or set a custom redirectStrategy. The default implementation calls response.sendRedirect(), but you can change that as you like in your custom implementation.
You will have some difficulty though, because neither of these configuration points are exposed through the namespace configuration, so you will need to go a level deeper, and write the bean definitions manually.
The redirect is controlled by the Redirect Strategy definined in the redirectStrategy property of SimpleUrlAuthenticationSuccessHandler.
The Default for redirectStrategy is an instance of DefaultRedirectStrategy.
What you need to do is to implement you own redirectStrategy (implements RedirectStrategy).
And then configure it:
...
<bean id="usernamePasswordAuthenticationFilter">
...
<property name="authenticationSuccessHandler">
<bean
class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<property name="redirectStrategy">
<bean class="yourRedirectStrategy"/>
<property>
</bean>
</property>
</bean>
I am having trouble connecting all the pieces that would allow xml sent from an ajax client to be unmarshalled into Java objects. I am using Jquery for the ajax client, Spring3, and JAXB. Here are the key components:
Ajax Client
function checkForNewActivities(activities) {
$j.ajax({
url: "upload/checkForNewActivities",
type: "POST",
async: true,
dataType: "xml",
data: ({activities:activities}),
contentType: "application/xml",
beforeSend: function() {
alert("sending ajax");
},
complete: function() {
alert("ajax sent");
},
success: function(data) {
alert("success");
},
error: function(jqXHR, textStatus, errorThrown) {
alert(textStatus + errorThrown);
}
});
}
Spring Config
<bean id="marshallingConverter" class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<property name="marshaller" ref="jaxbMarshaller" />
<property name="unmarshaller" ref="jaxbMarshaller" />
<property name="supportedMediaTypes" value="application/xml"/>
</bean>
<bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
a bunch of java classes
</list>
</property>
</bean>
And here is the Spring Controller method that is the target:
#RequestMapping(value="/checkForNewActivities",headers="application/xml", method=RequestMethod.POST)
public #ResponseBody String uploadMultipleWorkouts(#RequestBody String activities) {
System.out.println(activities);
return "";
}
With the headers="application/xml" in the RequestMapping, this method never gets called. If I remove the headers param, then the method is called and dumping the activities to the console shows the escaped xml.
I am clearly missing how to connect this method to the spring config so that unmarshalling xml takes place.
The reason your println prints out escaped xml is because the data type of the variable activities is String. You'll want to create a class to hold that data which will be passed to the method so there is a structure into which JAXB may translate the xml.
For example, instead of
public #ResponseBody String uploadMultipleWorkouts(#RequestBody String activities) {
You would want
public #ResponseBody Activities uploadMultipleWorkouts(#RequestBody Activities activities) {
Where Activities is a class you have defined with appropriate getters and setters such that the xml data you're passing in can be assigned. If the request data and response data must be different then you can simply define two classes, Request and Response variants.
As for why using headers="application/xml" messes things up, try setting it to headers = {"content-type=application/xml"}