grails keep a number of page under session - session

I am new to grails. I have recently used session in my controller. But for only one page. Now I want to use session for a number of pages. But I have no idea how to do it. Here is my code below which works for one page. Can anyone please help me on this ?
def index() {
def user = springSecurityService.currentUser
if (user){
redirect(controller: 'admistratorAction', action: 'createUser')
}else{
redirect(controller: 'login', action: 'index')
}
}

You may be new to Grails, I hope you are not new to HttpSession. :)
Session information is scoped only to the current web application
(ServletContext), so information stored in one context will not be
directly visible in another.
As long as you are in the same ServletContext you should be able to access session variable directly. Also look at Servlet API in grails.
#Alidad- Scroll back to last question from OP.

In that case you can take advantage of grails filter to do the check before execution of each action. As dmahapatro mentioned you can use session across your app to store user object and with this filter you can do a check before any action.
Something like this can help you achieve it.:
class SecurityFilters {
def filters = {
loginCheck(controller: '*', action: '*') {
before = {
if (!session.user)) {
redirect(action: 'login')
return false
}
}
}
}
}

Related

Passing TempData with RedirectToAction

Intro:
I am a .NET studet trying to learn ASP.NET Core MVC. So please be understanding. I have searched the web for an answer to my problem, but havent found a solution that works for me.
Problem:
I want to pass a validation message from my create post method to the index IActionmethod whenever a post has been created and them show it as an alert message for now. I have read on the web that ViewBag dosent survive a redirect, but a TempData does. This is my code so far.
Create post method:
public IActionResult CreatePost(string textContent, string headline, string type)
{
var catType = new Category() { CategoryType = type.ToUpper() };
if (db.Category.Any(s => s.CategoryType.Trim().ToLower() == type.Trim().ToLower()))
catType = db.Category.FirstOrDefault(s => s.CategoryType.Trim().ToLower() == type.Trim().ToLower());
var newPost = new Post()
{
Content = textContent,
Header = headline,
DateOfPost = DateTime.Now,
category = catType
};
db.Posts.Add(newPost);
db.SaveChanges();
TempData["validation"] = "Your post hase been publsihed";
return RedirectToAction("Index");
}
The index method:
public IActionResult Index()
{
var validation = TempData["validation"];
var posts = (from x in db.Posts
orderby x.DateOfPost descending
orderby x.PostID descending
select x);
return View(posts);
}
I have tried this guide: ClickThis and this one: ClickThis2 but I got this message:
I know this line from gudie number 2 might be important, but didnt now how to apply it. -
var product = TempData["myTempData"] as Product;
The last thing I want to do is pass it to the index view, but dont know how. I am currently passing a model from the index.
Tell me if it is anything more you would like to see. Like dependencies.
All the help I get is gold and will be much appreciate!!!
I landed on this question while googling for "asp.net core redirect to action tempdata". I found the answer and am posting it here for posterity.
Problem
My issue was that, after filling in some TempData values and calling RedirectToAction(), TempData would be empty on the page that I was redirecting to.
Solution
Per HamedH's answer here:
If you are running ASP.NET Core 2.1, open your Startup.cs file and make sure that in your Configure() method app.UseCookiePolicy(); comes after app.UseMVC();.
Example:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
...
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
app.UseCookiePolicy();
}
Did you configure Session? TempData is using session behind the scenes.
Project.json
"Microsoft.AspNetCore.Session": "1.1.0"
Here is the Startup.cs file. - ConfigureServices method
public void ConfigureServices(IServiceCollection services)
{
services.AddMemoryCache();
services.AddSession();
services.AddMvc();
}
And Configure method.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseSession();
app.UseMvc(routes => {
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
Now try with TempData, it will work.
And you can set the environment with set ASPNETCORE_ENVIRONMENT=Development environment variable.
TempData stores data server-side, under user Session. You need to enable sessions (as exception message says). Check this manual.
If you don't want to use sessions - you need some other way to store data (cookies?)
Providers
The TempData is using various providers for storing the state. By default the cookie based data provider is used.
Session is just an alternative
If your application do not use session I do not see any reason to use it only for TempData store.
Cookie Consent
ASP NET Core 2.1 have some new GDPR features based on cookies. By default, data should be stored in cookies only with the user's consent. If the user does not agree with the storing data in cookies, TempData cannot work. This behavior varies across versions of ASP NET Core.
If you do not want to hold any sensitive data in cookies, you can obviously change the settings.
app.UseCookiePolicy(new CookiePolicyOptions
{
CheckConsentNeeded = context => false
});
You can set the CookiePolicyOptions separatelly in ConfigureServices as well. It is a quite cleaner.
Story continues
We have two kind of data in the cookies. Essential data (needed for running application) and non-essential (some user data). User consent is needed for non-essential data. TempData is non-essential. You can set you TempData as essential and user consent is not needed anymore:
services.Configure<CookieTempDataProviderOptions>(options => {
options.Cookie.IsEssential = true;
});
I highly recommend to think about this before copy / paste.
I'm just posting this for anyone who comes across this problem in an ASP.NET MVC application, #Ahmar's answer made me go look at my logout method, I was using Session.Abandon() before redirecting to the login page.
I just changed it to Session.Clear() to reset the session instead of removing it completely and now the TempData is working in the method I'm redirecting to.

Best practice passing data to view model

I have a login view which lives in its own shell. Also I have adjusted the HttpClient to automatically redirect to the login shell if any http request returns an unauthorized state.
Additionally I'd like to show some textual info to the user on the login page, after he has been "forcefully" logged out. How can I pass the information (logoutReason in the code below) from MyHttpClient to the login shell/view model?
Here's some conceptual code:
login.js
// ...
export class Login {
username = '';
password = '';
error = '';
// ...
login() {
// ... login code ...
this.aurelia.setRoot('app'); // Switch to main app shell after login succeeded...
}
// ...
}
MyHttpClient.js
// ...
export default class {
// ...
configure() {
this.httpClient.configure(httpConfig => {
httpConfig.withInterceptor({
response(res) {
if (401 === res.status) {
this.aurelia.setRoot('login');
let logoutReason = res.serversLogoutReason;
// How should i pass the logoutReason to the login shell/view model?
}
return res;
}
}});
};
// ...
}
Solution:
I've chosen to take the "event" path as suggested in bluevoodoo1's comment with some adjustments:
MyHttpClient fires/publishes a new HttpUnauthorized event which holds the needed information (description text, etc.)
MyHttpClient doesn't change the shell anymore since the concrete handling of the 401 shouldn't be his concern
login.js subscribes to the HttpUnauthorized event, changes the shell & shows the desciption text...
I'm still open to any suggestions/improvement ideas to this solution since I'm not quite sure if this is the best way to go...
You could set a localStorage or sessionStorage value and then clear it after you have displayed it. What you are asking for is known as a flash message where it displays and then expires.
Within your response interceptor add something like the following:
sessionStorage.setItem('message-logoutReason', 'Session expired, please login again');
And then in the attached method inside of your login viewmodel, check for the value and clear it, like this:
attached() {
this.error = sessionStorage.getItem('message-logoutReason');
sessionStorage.removeItem('message-logoutReason');
}
Then in your view you can display it:
${error}
As Bluevoodoo1 points out, you could also use an event, but I personally try and avoid using events as much as possible, harder to test and debug when things go wrong.

Redirecting to a page if session object expires or user did not login to the application

This is a mvc application
I have the links below on my master page
Link1 Link2 Link3 signout signIn
I have a userprofile object that is populated
when authentication is done.
When the session object for the user expires
and I click on the links, I get the yellow page(error page).
I will prefer a situation where when you click on the
links and the session object is expired, you get
redirected to the signin page.
Soln A: I could solve this problem by writing a method
which test for null value of the userprofile object then
make a call to this method on the click on every link.
I dont want this approach because in the future if there
are new controllers, i will need to care for them.
Do you have any idea how I can solve this problem?
I would have a Base Controller than all of your other controllers inherit from. Within this I would have a
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (SessionManager.Instance() == null)
{
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary
{
{ "Controller", "BaseController" },
{ "Action", "LogOn" }
});
}
base.OnActionExecuting(filterContext);
}
The OnAction Executing will be hit before any method in any of your controllers - this way you can check your session is valid or your user is valid or whatever and handle the redirect to the view you want if that is not the case. If you do a Google search for Filters Actions MVC you will find out much more info.

how to use session in grails

I am new to grails. And I have to work with session. I have seen the session documentation. But no idea where to put the code in my controller. I have a page for student creation names createStudent. Now I want that this page only be access able when the user will be in session. Now how can I do it. Should I have to set the user in a variable at the time of login. Can anyone please help me on this ?
def index() {
def user = session["user"]
if (user){
redirect(controller: 'admistratorAction', action: 'createUser')
}else{
redirect(controller: 'login', action: 'index')
}
}
You could use the session.getAttribute(key) and session.setAttribute(key, value) methods inside your controller. Alternatively, there are plugins such as the Spring Security Core Plugin that already handle this very well.
There's a good tutorial by Peter Ledbrook for the Spring Security plugin here and the plugin documentation links to at least one other tutorial.
** Edit **
As you suggested, in order to use the session directly the user would need to be set in the session at an earlier point. For example:
def setCurrentStudent() {
def aStudent = [name: "Student1"]
session["user"] = aStudent
render "Added $aStudent to the session."
}
Spring Security will do this automatically at login. Then, the current user can then be accessed at any time using the springSecurityService.
class SomeController {
def springSecurityService
def someAction = {
def user = springSecurityService.currentUser
…
}
}

Different version of the cache in Symfony

I'm new in Symfony and I have a problem with logical code organisation.
The problem is connected with cache and different version of webpage for guests, logged in users and owner.
For example. I have 'user' module, which has 'show' action, and the URL is /user/show/:id and URL is the same for every visitor. But the content of the page depends on visitor and is selected with 'if' conditions so... If I clear the cache and the first visitor is guest, then others (including owner and logged in users) will see the guest's cached page.
Some kind of solution can be separating each view (owner, guest, logged in user) to partial, but it's against the DRY rule.
How to do this?
You can use the sf_cache_key parameter. See here how. I think you could use the user_id for logged in user, prepended with an arbitrary string for the owner, and for the guests, the string "guest" would do.
A bit of pseudo-code to help you further:
$sf_cache_key = '';
if ($visitor->isLogged())
{
if ($visitor->getId() == $userId )
{
$sf_cache_key = 'owner' . $userId;
}
else
{
$sf_cache_key = 'logged_in' . $userId;
}
}
else
{
$sf_cache_key = 'guest' . $userId;
}
I'm sure you solved this by now, and the app is already upgraded to the latest version. But I solved a similar problem generically by including a filter that sets a user-specific parameter in every URL preventing the data leak. This destroys reporting in GA, which is my current problem.
// Filter class in apps/frontend/lib/accessFilter.class.php
<?php
class accessFilter extends sfFilter
{
public function execute($filterChain)
{
$context = $this->getContext();
$context->getRouting()->setDefaultParameter('sw_user_id', $user_id);
$filterChain->execute();
}
}
// Filter definition in apps/frontend/config/filters.yml
# insert your own filters here
accessFilter:
class: accessFilter
// Use within routes in apps/frontend/config/routing.yml
dashboard:
url: /dashboard/:sw_user_id/home
param: { module: dashboard, action: index }

Resources