Session in Spring Rest - spring-boot

Hello i have a problem with session in spring rest i got everytime null in my session, this is my class
#GetMapping("/shoppingCart/addProduct/{productId}")
public ResponseEntity<Cart> addProductToCart(#PathVariable("productId") Long productId,HttpServletRequest request) throws AppException {
Product product = productService.getProduct(productId);
Cart cart= (Cart) request.getSession().getAttribute("myCart");
// If null, create it.
if (cart == null) {
cart = new Cart();
request.getSession().setAttribute("myCart", cart);
}
cart.addProduct(product, 1);
return new ResponseEntity<>(cart,HttpStatus.CREATED);
}
#GetMapping("/shoppingCart")
public ResponseEntity<Cart> shoppingCart(HttpServletRequest request) {
cart = (Cart) request.getSession().getAttribute("myCart");
return new ResponseEntity<>(cart,HttpStatus.CREATED);
}
this line request.getSession().getAttribute("myCart") returns null, and also when i add a product in my cart it saves in session for the first time after which when ever i try to add another product, my session is empty.
Thank you

RestFul services are inherently designed to be stateless, hence you should not be making use of session in a Rest API in the first place. But if you are somehow required to make use of the session as per you business logic then you should make use of Spring MVC instead of REST i.e. you should use #Controller annotation in the class and not #RestController.

Related

How do I change my controller into a REST controller? From Thymeleaf to Vue.js

For my university project, I have an up and running SpringBoot project using Thymeleaf, but I would now like to use Vue.js instead for my front end. To do this, I am wanting to change my controllers into REST Controllers but I'm struggling with how to go about that.
Here is an example of a method within the controller:
public String showQuiz(#PathVariable String subject, Model model) {
Session session = new Session();
session.setStart_time(new Timestamp(System.currentTimeMillis()));
List<Question> questions = questionService.getAllQuestionsBySubject(subject);
Quiz quiz = new Quiz(subject, questions, session);
session.setQuiz(quiz);
session.setScore(0);
ContextController.getEmployee().setSession(session);
session.setEmployeeId(ContextController.getEmployee().getId());
session.setEmployeeName(ContextController.getEmployee().getUsername());
ContextController.setSession(session); //optional shared context
sessionService.saveSession(session);
ContextController.questions = questions;
model.addAttribute("questions", questions);
AnswersDTO answersDto = new AnswersDTO();
model.addAttribute("answersDto", answersDto);
model.addAttribute("employee", ContextController.getEmployee());
return "quiz";
}
How would I convert the code above to return JSON?
Annotate your controller class #RestController. Return your data object wrapped in a org.springframework.http.ResponseEntity.
return ResponseEntity.ok().body(myDataObject);

Calling TableController.Lookup() from one controller on another controller fails

In an Azure Mobile App using the .NET backend, I need one controller to look up an entity handled by a second controller. For example, in the Todo Quickstart project from the Azure team, imagine adding a UserController which handles user management. In TodoItemController, I need to call UserController.GetUser(id) to check if a user is authorized to post a new TodoItem.
In TodoItemController.cs:
var userController = new UserController();
var user = userController.GetUser("12345");
if (user.IsAuthorized)
{
// Insert TodoItem
}
The above code throws an exception when TableController.Lookup() is called in UserController.GetUser(). The exception says that the request parameter cannot be null. My guess is that something is missing because I created the UserController myself, instead of it being created by the framework.
How can I make this work?
This appears to work in TodoItemController.cs:
var context = new todoProjectContext();
var userDomainManager = new EntityDomainManager<User>(context, Request);
var user = userDomainManager.Lookup(id).Queryable.FirstOrDefault();
if (user.isAuthorized)
{
// Insert item
}
Not sure it's the best solution though.

How to store PreRequestFilter information in AuthUserSession

I am building a web service using ServiceStack which has to support multiple vendors. The web service provides largely the same functionality to all vendors with some exceptions here and there.
In order to re-use as much functionality as possible I have come up with the following URL scheme:
http://localhost/brand1/templates
http://localhost/brand2/templates
"brand1" and "brand2" are not services but "templates" is. The Templates service's request DTO's will have a property called "Brand" like so:
[Route("/{Brand}/templates", "GET")]
public class GetTemplates
{
public Brand Brand { get; set; }
}
So in the Templates service I know which brand I am dealing with. This scheme works well.
What I cannot figure out though is this. The user of the service has to be authenticated and I cannot figure out how to handle the redirection of the service after the user has been authenticated since I have to pass along the brand information. I have created my own CustomAuthProvider class that inherits CredentialsAuthProvider. In the TryAuthenticate method I can set the authService.GetSession().ReferrerUrl property to the correct brand if I know what it was.
The only way I have found so far to get this information is to register a PreRequestFilter. My thinking here was that since the URL (e.g. http://localhost/brand1/templates) contains the brand I can store it in my own AuthUserSession class. I can't figure out how to do this. I have a "SessionFactory" method that I pass to the AuthFeature constructor. But what should I do in there? How do I get to the brand that I've obtained in the PreRequestFilter? Is it safe to store it in a field of the AppHost? I think not because of concurrency issues. How do I tie the PreRequestFilter to the SessionFactory method?
I hope I am explaining my problem clearly enough?
I was overthinking the solution because I didn't realize that I had all the information I needed in the IServiceBase parameter of the TryAuthenticate method of the CredentialsAuthProvider class.
In the end I came to the following solution:
public class CustomCredentialsAuthProvider : CredentialsAuthProvider
{
public override bool TryAuthenticate(IServiceBase authService,
string userName, string password)
{
var session = authService.GetSession();
var origQuery = authService.Request.UrlReferrer.Query;
session.ReferrerUrl = "/error";
var queryString = origQuery.Substring(10); // strip "redirect="
var decodedUrl = HttpUtility.UrlDecode(queryString);
if (!string.IsNullOrWhiteSpace(decodedUrl))
{
var query = new Uri(decodedUrl);
session.ReferrerUrl = query.AbsolutePath;
}
return DoAuthentication(userName, password);
}
}
The different places where you can set the Url to redirect to during ServiceStack Authentication, in order of precedence are:
The Session.ReferrerUrl Url if it's populated
The Continue QueryString, FormData param when making the request to /auth (i.e Authenticate.Continue property)
The HTTP Referer HTTP Header
The CallbackUrl of the current AuthProvider used

Grails + RESTful URL mapping + Filters + Routes

Member have many jobs. A member can add, delete or update Jobs. Currently there are actions (add, delete or update) defined in a controller which are called through jQuery.ajax(). We are sending job id and member id to perform the operation. Member id is necessary because there is a role admin who can modify the job on behalf of members, so we need to identify the member. But sending member id is dangerous as anyone can send the request by modifying the member id.
I know, we can add constraint do restrict that only admin can modify the jobs or a member can modify only his jobs. My question is, Do I need to add these constraints in the action of the controller or Is there any Grails way to do that. I have google, the same thing is handled in Ruby and Rails by using routes. And in grails I have skim through RESTful URL mapping, which is perhaps used for this purpose.
Can anyone points me to right direction, thanks. I am using Grails 2.1.1.
You can implement some realization of AbstractPersistenceEventListenerService to not allow perform actions with entity that constains id of not logged in user. Example:
class MultiTenantPersistenceEventListenerService extends AbstractPersistenceEventListenerService {
def springSecurityService
#Override
protected AbstractPersistenceEventListener createPersistenceEventListener(Datastore datastore) {
return new MultiTenantPersistenceEventListener(datastore)
}
}
class MultiTenantPersistenceEventListener extends AbstractPersistenceEventListener {
MultiTenantPersistenceEventListener(final Datastore datastore) {
super(datastore)
}
#Override
protected void onPersistenceEvent(AbstractPersistenceEvent event) {
def entity = event.getEntityObject() // could be your Job domain entity
def user = springSecurityService.getCurrentUser() //current logged in user
if(entity.hasProperty('userId')){ // every job belongs to User
if(entity.userId != user.id){
throw new AccessDeniedException("Acces Denied !")
}
}
}
}
I'd recomment to use grails spring-security-plugin. There is a lot of information in web about plugin and it's easy configurable. Plugin allows you to perfrom controller's action in secure way. For example:
#Secured(['ROLE_USER'])
def followAjax = { ... }
#Secured(['IS_AUTHENTICATED_REMEMBERED'])
def personal = { ... }
For more information - plugin and spring-security with grails.
You can use Authorize attribute to authorize the user,
e.g
[CustomAuthorize(Roles=SiteRoles.Admin|SiteRoles.HelpDesk)]
public ActionResult Index()
{
return View();
}
This is a nice approach for making website secure.
go through these link, this will help you.
custom authorization with asp.net mvc
asp.net mvc authorization

How to prevent duplicate form submission in ASP.NET MVC 3?

I have a razor view that renders a html form and it posts to the server.
If the form values are right then it gets saved to database.
After insertion, I redirect to another view where user can make further changes.
Right now the user can hit browser back button and resubmit the form to create another record in db.
How do I prevent duplicate submission in my MVC app?
One solution is to put a hidden "token" field on the form that's generated randomly when the form loads. When you see that token come back on creation store it somewhere temporarily (in session if you're using sessions for example). If you see the same one again, you can assume the same form was submitted twice quickly together.
Create a cookie to represent that particular page when it succeeds. If it is replayed with the cookie (which the browser would now send over with every request) you know not to allow the new attempt.
Redirect the user to another HttpGet action after handling the post request.
So that when the user refreshes the browser the post action will not be called again.
return RedirectToAction("YourActionMethod");
Although client side validation is possible, it is not secure enough.
I am not sure if this method applies to MVC 3, but what i did is implement a ActionFilterAttribute
here is the implementation:
public class PreventFrequentCallsAttribute : ActionFilterAttribute
{
public int DelayRequest = 5;
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var request = filterContext.HttpContext.Request;
var cache = filterContext.HttpContext.Cache;
var originationInfo = request.ServerVariables["HTTP_X_FORWARDED_FOR"] ?? request.UserHostAddress;
originationInfo += request.UserAgent;
var targetInfo = request.RawUrl + request.QueryString;
var hashValue = string.Join("", MD5.Create().ComputeHash(Encoding.ASCII.GetBytes(originationInfo + targetInfo)).Select(s => s.ToString("x2")));
if (cache[hashValue] != null)
{
filterContext.Controller.ViewData.ModelState.AddModelError("ExcessiveRequests", "Excessive Request Attempts Detected.");
}
else
{
cache.Add(hashValue, originationInfo, null, DateTime.Now.AddSeconds(DelayRequest), Cache.NoSlidingExpiration, CacheItemPriority.Default, null);
}
base.OnActionExecuting(filterContext);
}
}
later, in the target controller, just add this attribute:
[PreventFrequentCalls(3)]
public PartialViewResult LogOn(LogOnViewModel model)

Resources