For some reason when I execute a GET request to a certain URI the variable that I need to access in that method loses its memory or points to null.
I have a form where a user can update his personal information. But when he enters a duplicate, it redirects him to a page that lets him know
I have : private static volatile User currentUser;
This field is set when a user logs in and the server performs a GET request to a REST API, which I programmed myself, and returns the User containing his info. This works as expected and the user info is displayed on his home screen.
Code for the above:
#RequestMapping(value = "/login", method = RequestMethod.POST)
public String login(#ModelAttribute Credentials credentials,
RedirectAttributes redirect) {
RestTemplate restTemplate = new RestTemplate();
RoleInfo roleInfo = restTemplate.postForObject(
"http://localhost:9090/users/login", credentials,
RoleInfo.class);
if (roleInfo != null) {
if (roleInfo.isAdmin()) {
redirect.addFlashAttribute("credentials", credentials);
return "redirect:/adminHome";
} else {
redirect.addFlashAttribute("credentials", credentials);
return "redirect:/getBasicUser";
}
} else {
return "login_fail";
}
}
#RequestMapping(value = "/getBasicUser", method = RequestMethod.GET)
public <T> String getBasicUser(#ModelAttribute Credentials credentials,
Model model, RedirectAttributes redirect) {
RestTemplate restTemplate = new RestTemplate();
String url = "http://localhost:9090/users/getBasicUser?username="
+ credentials.getUsername();
ResponseEntity<User> responseEntity = restTemplate.exchange(
url,
HttpMethod.GET,
new HttpEntity<T>(createHeaders(credentials.getUsername(),
credentials.getPassword())), User.class);
User user;
user = responseEntity.getBody();
currentUser = user;
System.out.println("current user: " + currentUser.getUsername());
if (user != null) {
userName = credentials.getUsername();
passWord = credentials.getPassword();
redirect.addFlashAttribute("credentials", credentials);
redirect.addFlashAttribute("user", user);
return "redirect:/basicHome";
} else {
return "register_fail";
}
}
So on "basicHome" he can view his information. Also on that page is a link to a form where he can edit the information:
#RequestMapping(value = "/edit", method = RequestMethod.GET)
public String getEditProfilePage(Model model) {
model.addAttribute("currentUser", currentUser);
System.out.println("current use firstname: " + currentUser.getFirstname());
model.addAttribute("user", new User());
return "edit_profile";
}
If an edit is successful he is returned back to his home page with the updated information.
The problem comes when he enters invalid info. He should be redirected back to the "/edit" URI and the currentUserfield should still hold his information but is actually null.
Here is the "/edit" PUT function:
#RequestMapping(value = "/edit", method = RequestMethod.PUT)
public <T> String editProfile(#ModelAttribute("user") User user,
#ModelAttribute("credentials") Credentials credentials,
RedirectAttributes redirect) {
RestTemplate restTemplate = new RestTemplate();
String url = "http://localhost:9090/users/update?username=" + userName;
HttpHeaders headers = createHeaders(userName,
passWord);
#SuppressWarnings({ "unchecked", "rawtypes" })
HttpEntity<T> entity = new HttpEntity(user, headers);
ResponseEntity<User> responseEntity = restTemplate.exchange(url,
HttpMethod.PUT, entity, User.class);
User returnedUser = responseEntity.getBody();
currentUser = returnedUser;
if (returnedUser != null) {
redirect.addFlashAttribute("user", returnedUser);
redirect.addFlashAttribute("credentials", credentials);
return "redirect:/basicHome";
} else {
return "redirect:/editFail";
}
}
I figured out what I had to do. I basically made "user" a session object in: #SessionAttributes("user")
Related
I'm writing some code for user authorization. For users with 2 factored authorization enabled I'm writing code for 2fa secret update:
#RestController
public class CurrentUserController {
#PostMapping(value = "update-2fa-secret", produces = MediaType.IMAGE_JPEG_VALUE)
public byte[] update2FaSecret() {
UserEntity user = userRepository.findOne(currentUserId);
if (user.is2FaEnabled() != Boolean.TRUE)
throw new HttpForbiddenException("2fa disabled for current user");
String secret = createNewSecret();
user.setSecret2Fa(secret);
userRepository.save(user);
return createQRCode(secret, user.getEmail());
}
}
And Exception:
#ResponseStatus(HttpStatus.FORBIDDEN)
public class HttpForbiddenException extends RuntimeException {
............
}
And when Exception happens I get response from the server with 406 Http status and without body (content).
I don't understand why this happens and how to solve it. Can somebody explain it to me please?
I've solved this issue in the next way:
#RestController
public class CurrentUserController {
#PostMapping(value = "update-2fa-secret", produces = MediaType.IMAGE_JPEG_VALUE)
public byte[] update2FaSecret(HttpServletResponse response) {
UserEntity user = userRepository.findOne(currentUserId);
if (user.is2FaEnabled() != Boolean.TRUE) { //fix is here
response.setStatus(HttpStatus.FORBIDDEN.value()); //403
return new byte[0];
}
String secret = createNewSecret();
user.setSecret2Fa(secret);
userRepository.save(user);
return createQRCode(secret, user.getEmail());
}
}
Redirection does not work properly. I could not understand the problem because I very new to spring.
Here is my controller when I submit my form then ("schoolform") submitForm controller called and it redirect to another controller to ('form') form controller but it goes to ("login") login controller. I don't know why ?
I want to redirect schoolform to form controller.
#RequestMapping(value = "/schoolform", method = RequestMethod.POST)
public String submitForm(#ModelAttribute("school")School school,Model model,HttpServletRequest request,HttpServletResponse resp) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
schoolService.update(school);
System.out.println("Form submitted finaly, No further changes can be made.");
return "redirect:/form.html";
}
#RequestMapping(value = "/form", method = RequestMethod.GET)
public String form(Model model,HttpServletRequest request) {
HttpSession session = request.getSession(true);
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String name = auth.getName(); // get logged in username
System.out.println(name+"--------form page-----");
}
#RequestMapping(value = "/login", method = RequestMethod.GET)
public ModelAndView login(
#RequestParam(value = "error", required = false) String error,
#RequestParam(value = "logout", required = false) String logout) {
logger.info("------------------LoginController ---------------");
System.out.println("LoginController ");
ModelAndView model = new ModelAndView();
if (error != null) {
model.addObject("error", "Invalid username and password!");
}
if (logout != null) {
model.addObject("msg", "You've been logged out successfully.");
}
model.setViewName("login");
return model;
}
I think it is not working because the method in which you are trying to redirect to a url, accepts POST requests. You cannot redirect from POST methods UNLESS you have a handler method that accepts GET method and whose #RequestMapping accepts the value where you are trying to redirect.
So basically, the method submitForm which accepts POST requests only, is trying to redirect to /form.html. Now, there is no method in your controller that accepts /form.html, So now you gotto have a method in your controller class whose mapping value is /form.html and it accepts GET requests:
#RequestMapping(value = "/form.html", method = RequestMethod.GET)
public String methodName(arg1 ..){ ... }
When i successfully logged in (using logincontroller), I can see the session attribute "user" value.
FOR EXAMPLE:
-- in logincontroller --
#RequestMapping(value = "/login", method=RequestMethod.POST)
public String logIn(HttpServletRequest request, HttpServletResponse response, ModelMap map){
String email = request.getParameter("email");
String password = request.getParameter("password");
System.out.println("Login function is called.");
List<UsersModule> list = loginModuleService.getLoginDetails(email,password);
UsersModule foundEntity = new UsersModule();
HttpSession session = null;
if(!list.isEmpty() && email != null && !email.equals("") && !email.trim().equals("") && password != null && !password.equals("") && !password.trim().equals("")){
//ignores multiple results
foundEntity = list.get(0);
session = request.getSession();
session.setAttribute("user", foundEntity.getFamilyName()+", "+foundEntity.getFirstName());
session.setMaxInactiveInterval(60*60);
return "home";
}else{
System.out.println("Empty? "+Boolean.toString(list.isEmpty()));
System.out.println("Email "+email);
System.out.println("Password "+password);
map.addAttribute("error", "Incorrect Email/Password");
return "login";
}
}
-- in home.jsp --
I can see the User value being displayed in the page.
But when i go to another page (using another controller), it redirects to login page. And I think its because the session attribute "user" is null. I put a condition if user is null, it will go back to login page.
-- another controller --
#RequestMapping(value = "/home", method = RequestMethod.GET)
public String Home(HttpServletRequest request,
HttpServletResponse response, ModelMap map) {
HttpSession session= request.getSession();
boolean isLogged= session.getAttribute("user")!=null;
if(isLogged){
return "home";
}else{
return "/index"; // redirect to login page if session is not established
}
}
#RequestMapping("/list")
public String list(HttpServletRequest request,
HttpServletResponse response, ModelMap map) {
HttpSession session= request.getSession();
boolean isLogged=session.getAttribute("user")!=null;
if(isLogged){
String searchTerm = request.getParameter("searchTerm");
String paging = request.getParameter("paging");
int page = 0; //pagination not yet working
List<UsersModule> list = usersModuleService.getUsersList(searchTerm,
page);
map.addAttribute("usersList", list);
return "usersmodule/list"; // go to users list page
}else{
return "/index"; // redirect to login page if session is not established
}
}
-- list.jsp--
When i go to another page like this, I cannot see the User value and i am redirected to the login page.
I cannot solve how to keep the session attribute values when going to another webpages. I have tried all the resources i could find but it still the same. :(
public String logIn(HtppSession session,HttpServletRequest request, HttpServletResponse response, ModelMap map){}
define HttpSession as a variable of login method.
I am implementing a project RESTful API, it should login (username / password) and returns a token, I want to use token to retrieve user information.
I follow the instructions:
https://github.com/virgo47/restful-spring-security
But: I do not know how to use it in my function, you can help me with?
#RequestMapping(value = "/login", method = RequestMethod.POST)
public #ResponseBody ResponseObject<Object> login(
#RequestParam(value = "username", required = true) String username,
#RequestParam(value = "password", required = true) String password,
#RequestHeader(value = "token") String token,
HttpSession session) {
//TODO
return new ResponseObject<Object>(1, "Success", data);
}
#RequestMapping(value = "/info", method = RequestMethod.GET)
public #ResponseBody ResponseObject<User> getInfo(#RequestHeader(value = "token", required = true) String token,
HttpSession session) {
//TODO
return null;
}
Why would you want to do that ? Why not just get the logged in user from the SecurityContext as follows
#RequestMapping(value = "/test", method = RequestMethod.GET)
public String test() {
System.out.println(" *** MainRestController.test");
// Spring Security dependency is unwanted in controller, typically some
// #Component (UserContext) hides it.
// Not that we don't use Spring Security annotations anyway...
return "SecurityContext: "
+ SecurityContextHolder.getContext().getAuthentication()
.getName();
}
If you insist on doing it, you can do the following.
UserDetails userDetails =
(UserDetails)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
tokenManager.getUserTokens(userDetails)
Currently path is showing
http://localhost:8081/UserLogin/login
But i want this as
http://localhost:8081/UserLogin/index
or
http://localhost:8081/UserLogin/
My controller class is
#RequestMapping(value = "/login" ,method = RequestMethod.POST)
public ModelAndView test(HttpServletRequest request, HttpServletResponse response) {
//return "hi this is a test";
String userName = request.getParameter("data[Admin][user_name]");
String userPass=request.getParameter("data[Admin][password]");
int userId=userDAO.getUser(userName, userPass);
if(userId!=0){
String message = "welcome!!!";
return new ModelAndView("result", "message", message);
}
else{
String message = "fail";
return new ModelAndView("index", "message",message);
}
}
Want to change in else condition when not match.
Thanks in advance. :)
I would return a redirect to render the view under the new URL:
request.addAttribute("message",message) // better use a Model
return "redirect:/[SERVLET_MAPPING]/index";
It take some time to understand what you want: - I guess you want to alter the URL that is returned from the Server after login.
But this does not work this way, because the URL is requested from the browser and the server can not change them. Instead the server can respond an "HTTP 303 Redirect" (instead of the view). This cause the Browser to load the URL given with the Redirect.
#RequestMapping(value = "/login" ,method = RequestMethod.POST)
public ModelAndView test(HttpServletRequest request, HttpServletResponse response) {
//return "hi this is a test";
String userName = request.getParameter("data[Admin][user_name]");
String userPass=request.getParameter("data[Admin][password]");
int userId=userDAO.getUser(userName, userPass);
if(userId!=0){
return new ModelAndView(new RedirectView("/result", true)); // "/result" this is/become an URL!
}
else {
return new ModelAndView(new RedirectView("/index", true)); // "/index" this is/become an URL!
}
}
#RequestMapping(value = "/index" ,method = RequestMethod.GET)
public ModelAndView test(HttpServletRequest request, HttpServletResponse response) {
String message = "fail";
return new ModelAndView("index", "message",message); //"index" the the name of an jsp (or other template)!!
}
#RequestMapping(value = "/result" ,method = RequestMethod.GET)
public ModelAndView test(HttpServletRequest request, HttpServletResponse response) {
String message = "welcome!!!";
return new ModelAndView("result", "message", message); //"result" the the name of an jsp (or other template)!!
}
#See http://en.wikipedia.org/wiki/URL_redirection