Redirect to another page from _Layout.cshtml - asp.net-mvc

How to redirect to another page within the _layout.cshtm page in asp.net core razor.
I am doing the verification and user is logged in, if not it will be redirected to another page.
#using Microsoft.AspNetCore.Identity
#using CronoParque.Model
#inject SignInManager<ApplicationUser> SignInManager
#inject UserManager<ApplicationUser> UserManager
#if (SignInManager.IsSignedIn(User))
{
<form asp-controller="Account" asp-action="Logout" method="post" id="logoutForm" class="navbar-right">
<ul class="nav navbar-nav navbar-right">
<li>
<a asp-page="/Account/Manage/Index" title="Manage">Ola #UserManager.GetUserName(User)!</a>
</li>
<li>
<button type="submit" class="btn btn-link navbar-btn navbar-link">Sair</button>
</li>
</ul>
</form>
}
else
{
// targeting here
}

Answer
#if (SignInManager.IsSignedIn(User))
{
// normal stuff
}
else if (!Context.Request.Path.ToString().Contains("/About"))
{
// If we aren't processing a request for the target page,
// then redirect to it.
Context.Response.Redirect("/About");
}
Maybe a Better Answer
The use case for your question might be to redirect unauthorized requests to a log in page. In that case, use the built-in razor pages authorization API.
services
.AddMvc()
.AddRazorPagesOptions(options => {
options.Conventions.AuthorizePage("/Contact");
});
The above code goes into the Startup > ConfigureServices method.
In the above example, the API redirects unauthorized requests for the /Contact.
See also: https://learn.microsoft.com/en-us/aspnet/core/security/authorization/razor-pages-authorization?view=aspnetcore-2.1#require-authorization-to-access-a-page

Related

Why does HttpContext.User.Identity.Name contain the wrong name?

I have a .NET 5 MVC application that periodically checks access based on the HttpContext.User.Identity.Name value. The app uses Azure AD. Sometimes as I switch between users (Signing out and Signing in), the HttpContext.User.Identity.Name value will contain the previous user's name and the current user will have the access of the previous user.
Even more strange is the the login shown is correct.
This is just the boiler plate code generated by visual studio:
#using System.Security.Principal
<ul class="navbar-nav">
#if (User.Identity.IsAuthenticated)
{
<li class="nav-item">
<span class="navbar-text text-light">Hello #User.Identity.Name!</span>
</li>
<li class="nav-item">
<a class="nav-link text-light" asp-area="MicrosoftIdentity" asp-controller="Account" asp-action="SignOut">Sign out</a>
</li>
}
else
{
<li class="nav-item">
<a class="nav-link text-light" asp-area="MicrosoftIdentity" asp-controller="Account" asp-action="SignIn">Sign in</a>
</li>
}
</ul>
So #User.Identity.Name on the .cshtml is always correct, but HttpContext.User.Identity.Name on the controller is the previous (cached?) user.
Any clues to why the previous user gets cached?
Here is a sample of how I call it on the controller:
ViewData["User"] = HttpContext.User;
ViewData["Menu"] = await _menuService.GetReportMenuAsync(MenuService.ReportMenuItemOption.Genesis01, User.Identity.Name);
var userAccess = await _userAccessService.GetUserEntityAccessAsync(User.Identity.Name);
var model = new SomeModel
{
SearchDate = DateTime.Now.AddDays(-7),
Banks = userAccess.Banks,
ATMIds = userAccess.ATMs
};
return View(model);
This is in my StartUp:
services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
}).AddMicrosoftIdentityUI();

How to get the dynamic data of fragment to another page using thymelleaf

I want to get the information(which is dynamically generated) from one html page into another html page.
I used a tag th:fragment in first html page and th:replace in second html page.
But i am getting only static content of first page, is it possible to get the dynamic data or not? can anyone help me please.
Thanks in advance.
Here is my Java code :
#Controller
public class WelcomeController {
#RequestMapping("/")
public ModelAndView usingToList(Model model) {
List<String> colors = new ArrayList<>();
colors.add("green");
colors.add("yellow");
colors.add("red");
colors.add("blue");
model.addAttribute("message", "harika");
model.addAttribute("colors", colors);
List<String> colors2 = new ArrayList<>();
colors2.add("pinkish");
colors2.add("green");
colors2.add("yellow");
colors2.add("red");
colors2.add("blue");
model.addAttribute("coloring", colors2);
ModelAndView mv = new ModelAndView();
mv.setViewName("welcome");
return mv;
}
#GetMapping("/toList")
public String usingToList2(Model model,String color) {
System.out.println("inside uselist");
List<String> colors2 = new ArrayList<>();
if(color.equals("pinkish"))
{
colors2.add("pinkish");
colors2.add("amity");
colors2.add("pimity");
}
if(color.equals("green"))
{
colors2.add("greenish");
colors2.add("amity");
colors2.add("Pretty");
}
model.addAttribute("colors", colors2);
return "welcome";
}
}
Below is my sample POC :
here is my fragment: nav.html which it load the colors dynamically. I am using this side bar fragment in all the pages. When I go another page, data in the side bar is disappering.
<div th:fragment="sidebar2">
<div class="sidebar-sticky pt-3">
<ul class="nav flex-column" id="accordionSidebar">
<li class="nav-item">
<a type="button"
id="collapse"
data-toggle="collapse"
data-target="#collapseExample"
aria-expanded="false" aria-
controls="collapseExample">
<span class="menu-title">Colors List</span>
<span data-feather="plus-circle"></span>
</a>
<div class="collapse" id="collapseExample">
<ul class="nav flex-column sub-menu"
id="collapseExample2">
<li th:each="color :
${coloring}">
<a th:href="#{/toList(color=${color})}"
th:text="${color}"> ></a>
</li>
</ul>
</div>
</div>
welcome.html:
<div th:replace="fragments/nav :: sidebar2"></div>
<main role="main" class="container">
<div class="starter-template">
<h1>Spring Boot Web Thymeleaf Example</h1>
<h2>
<span th:text="'Hello, ' + ${message}"></span>
</h2>
</div>
<ol>
<li th:each="color2 : ${colors}" th:text="${color2}"></li>
</ol>
</main>
When you navigate from one page to another, the Model is empty again (unless you are doing a <form> POST).
When you show the welcome.html Thymeleaf template via usingToList2(), then there is nothing in the Model for the coloring key.
To solve it, also add the coloring key in the usingToList2() controller method.
UPDATE: If all controllers need it, you can use #ControllerAdvice:
#ControllerAdvice
public class GlobalControllerAdvice {
#ModelAttribute("coloring")
public List<String> coloring() {
List<String> colors2 = new ArrayList<>();
colors2.add("pinkish");
colors2.add("green");
colors2.add("yellow");
colors2.add("red");
colors2.add("blue");
}
}
Or if all methods in a single controller need it, you can just add that method in the controller class itself.

Why User.Identity.IsAuthenticated is always true even after logout

I am working on AspnetCore 2.1 MVC application , it has windows integrated authentication. I have implemented login, logout functionality using await HttpContext.SignInAsync(). it is cookie bases authentication, the cookie expires after specified time I provide.
My issue is I have to hide logout from nav bar after user logs out. but in _layout.cshtml , #User.Identity.Is authenticated always true even after user hits logout. Any help ? below is the code I am using
<div class="navbar-collapse collapse">
#if(User.Identity.IsAuthenticated)
{
<ul class="nav navbar-nav">
<li><a asp-area="" asp-controller="Home" asp-action="Index">Home</a></li>
<li><a asp-area="" asp-controller="InitiatedCases" asp-action="Index">Initiated Cases</a></li>
<li><a asp-area="" asp-controller="SubmittedCases" asp-action="Index">Submitted Cases</a></li>
<li><a asp-area="" asp-controller="UserAccessLogs" asp-action="Index">User Access Log</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><a asp-controller="Account" asp-action="Logout">Logout</a></li>
<li><p class="nav navbar-text navbar-right">#User.Identity.Name!</p></li>
</ul>
}
else
{
<p></p>
}
</div>
below is login functionality
var usrRole = _dbContext.UserAccess.Where(r => r.UserId == loginUser.UserId).FirstOrDefault();
var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);
identity.AddClaim(new Claim(ClaimTypes.Name, loginUser.UserId.ToString()));
identity.AddClaim(new Claim("DisplayName", loginUser.UserId));
if (usrRole != null)
{
identity.AddClaim(new Claim(ClaimTypes.Role, usrRole.UserRole.ToString()));
}
await HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(identity),
new AuthenticationProperties
{
IsPersistent = true,
IssuedUtc = DateTime.Now,
ExpiresUtc = DateTime.Now.AddMinutes(_iconfiguration.GetValue<double>("Session:TimeOutInMinutes")),
AllowRefresh = false
});
I think you may be using windows integrated authentication - although i am not sure.
The browser uses Windows Integrated Authentication - which means it automatically logs the user in using their windows credentials - without asking.
That's why IsAuthenticated is always true.
Additional thoughts:
I have not tried below code, but there is something called as IISServerOptions.
You can try them to check if that works for you.
services.Configure<IISServerOptions>(options =>
{
options.AutomaticAuthentication = false;
});

ASP.net MVC unable to call POST Logout method

I've been trying to perform Logout operation (Form Authentication with cookies) but unable to call the POST Logout action method.
Here's my Partial View:
<nav class="navbar navbar-inverse" role="navigation">
<div class="container">
<div class="nav navbar-nav navbar-right">
#using (Html.BeginForm("Logoff", "Account", FormMethod.Post, new { id = "logoutForm" }))
{
#Html.AntiForgeryToken()
<a class="navbar-brand" href="javascript:document.getElementById('logoutForm').submit()" title="Logout">
<img alt="Home" src="#Url.Content(" ~/Images/logout.png ")"/>
</a>
}
</div>
</div>
</nav>
I'm calling this partial View in below Home page as header:
<header role="banner">
#Html.Partial("_HomeHeader")
</header>
<div class="container">
.......
</div>
In my account controller, I've defined following action method:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Logoff()
{
FormsAuthentication.SignOut();
Session.Clear();
return Redirect(FormsAuthentication.LoginUrl);
}
Thus, on clicking the Logout button from the home page, it should Go to the "Logoff" action method and clear the cookies and then redirect to Login Page.
But it doesn't work.
Instead, it goes to the Login page directly without visiting the Logoff action method. I got this URL:
http://localhost/Account/Login?ReturnUrl=%2FAccount%2FLogoff
Can anyone please provide their inputs regarding how to achieve this functionality?
I know you already far in the process but you could use the WebSecurity method instead of your action method in your action controller... (OathWebsecurity, WebSecurity.Logout();... etc)
Try the below code, Hope it Helps.!
<a class="navbar-brand" href="javascript:submitform()" title="Logout">
<img alt="Home" src="#Url.Content(" ~/Images/logout.png ")"/>
</a>
<script type="text/javascript">
function submitform()
{
$("#logoutForm").submit();
}
</script>

unable to call LogOff method in controller

I have started a project using MVC6 and can't seem to route to the LogOff method.
The account controller looks like this:
//
// POST: /Account/LogOff
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> LogOff()
{
await _signInManager.SignOutAsync();
_logger.LogInformation(4, "User logged out.");
return RedirectToAction(nameof(HomeController.Index), "Home");
}
The calling navigation looks like this:
#if (User.IsSignedIn())
{
<div class="profile-picture">
<div class="stats-label text-color">
<span class="font-extra-bold font-uppercase">#User.GetUserName()</span>
<div class="dropdown">
<a class="dropdown-toggle" href="#" data-toggle="dropdown">
<small class="text-muted">Title <b class="caret"></b></small>
</a>
<ul class="dropdown-menu animated flipInX m-t-xs">
<li>Log off</li>
<li>Link 2</li>
<li>Link 3</li>
</ul>
</div>
</div>
</div>
}
I have applied a break point in the on the first line of the method in the controller however it never breaks on it and the browser just goes blank.
What am I doing wrong?
Instead of
<li>Log off</li>
Try replacing like this:
#using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm" }))
{
#Html.AntiForgeryToken()
<li>Log off</li>
}

Resources