Thymeleaf with Spring Security - how to check if user is logged in or not? - spring

I'm using Spring Boot with Thymeleaf and Spring Security.
I've got a simple view with a login link. When the user logs in, I'd like to change login link to logout link.
I tried:
<div sec:authorize="#{isAuthenticated()}">
<a th:href="#{/logout}">Log out</a>
</div>
<div sec:authorize="#{isAnonymous()}">
<a th:href="#{/login}">Log in</a>
</div>
but it's not working - it displays both links.
EDIT:
I solved it. I had to register Thymeleaf dialect. In order to do this, I created a new config class, that creates SpringSecurityDialect bean:
#Configuration
public class ThymeleafConfig {
#Bean
public SpringSecurityDialect springSecurityDialect(){
return new SpringSecurityDialect();
}
}

According to thymeleaf docs no spel expression is required. This is not a th: attribute.
So you may try :
<div sec:authorize="isAuthenticated()">
<div sec:authorize="isAnonymous()">

also you can use:
<ul>
<li sec:authorize="isAnonymous()"><a class="nav-link" href="/login">Login</a></li>
<li sec:authorize="isAuthenticated()"><a class="nav-link" href="/logout">Logout</a></li>
<li sec:authorize="isAuthenticated()">Wellcome, <span sec:authentication="name"></span></li>
</ul>
to get de current loged user.

Can also use sec:authorize="isFullyAuthenticated()" which checks if its an anonymousUser and rememberMe.
<div class="button-group" sec:authorize="!isFullyAuthenticated()">
Login
Register
</div>
<div class="button-group" sec:authorize="isFullyAuthenticated()">
Logout
</div>

Following did not work for me for 3.0.4.RELEASE thymeleaf-extras-springsecurity4:
<div sec:authorize="isAnonymous()">
Instead, following worked:
<div th:if="${#authentication == null}">

Related

Spring boot Application with Thymeleaf. Using Constants to check hasAuthority

Defined constants in my class and using in UI to validate if user have the authority, show the menu to user else hide it. refer below code the way I implemented.
<li sec:authorize="hasAuthority('${T(com.sample.application.security.Privilege).ADMIN}')" class="nav-item" th:classappend="${template} == 'Home' ? 'active':''">
However, its not working as I expect. I was expecting thymeleaf to transform ${T(com.sample.application.security.Privilege).ADMIN} to ADMIN and verify it as hasAuthority('ADMIN') but thats not working. Is there any other way to do this validation in thymeleaf. Whats the best approach to get this implemented?
Update: Tried with assigning the constants to thymeleaf local variable as well. Didnt work either.
<ul class="navbar-nav" th:with="admin=${T(com.sample.application.security.Privilege).ADMINISTRATOR}, groupAdmin=${T(com.sample.application.security.Privilege).APPLICATION_GROUP_ADMIN}, basicUser=${T(com.sample.application.security.Privilege).APPLICATION_BASIC_USER}" >
<li sec:authorize="hasAuthority(${basicUser}) OR hasAuthority(${admin})" class="nav-item" th:classappend="${template} == 'home' ? 'active':''">
<a class="nav-link" href="/myApplication/User">Customer Home</a>
</li>......</ul>
After trying several ways. Below solution worked without any issue.
<ul class="navbar-nav">
<li sec:authorize="${hasAuthority(T(com.sample.application.security.Privilege).ADMINISTRATOR) OR hasAuthority(T(com.sample.application.security.Privilege).APPLICATION_GROUP_ADMIN)}" class="nav-item" th:classappend="${template} == 'home' ? 'active':''">
<a class="nav-link" href="/myApplication/User">Customer Home</a>
</li>

Views and downloads count - Update database on view with lightbox and download

I've made a site with laravel and have a page where there are pictures that can be seen in hi-resolution via fancybox or downloaded. In the database i have counters for each action. and I do already have GET routes set up for the counting since they are used in other situations too.
for example: www.mysiste.com/somecode/someothercode/image/viewed
the simplified structure of each image is this.. This is called inside a for each loop.. i removed all styling and classes for better reading...
<div >
<div class="card" style="background-color: lightgray">
<div >
<a data-fancybox="gallery" href="/images/......../{{$photo->filename}}">
<img class="card-img" src="/images/......../thumb/thumb_{{$photo->filename}}">
</a>
</div>
<div class="card-footer">
<div>
<div>
<a download="{{$photo->filename}}" href="/images/......../{{$photo->filename}}">
<span>Download (Hi-Res)</span>
</a>
</div>
<div>
<a download="social_{{$photo->filename}}" href="/images/......../social_{{$photo->filename}}">
<span>Download (Social-Res)</span>
</a>
</div>
</div>
</div>
</div>
</div>
I would need that when they hit the download button it calls a certain URL in the background for upcounting.. (most important)
If possible I would like to hit another URL when the images are viewed fullscreen through fancybox.
how can this be done?
You can do something in the lines of:
<a data-fancybox="gallery" href="{{ route('photo.fancybox', ['photo' => $photo])}}">
<img class="card-img" src="/images/......../thumb/thumb_{{$photo->filename}}">
</a>
...
<a href="{{ route('photo.download', ['photo' => $photo])}}">
<span>Download (Hi-Res)</span>
</a>
PhotoController
public function download(Photo $photo){
$photo->downloadCount->increment();
return redirect('/images/......../'. $photo->filename);
}
public function fancybox(Photo $photo){
$photo->fancyboxCount->increment();
return redirect('/images/......../social_'. $photo->filename);
}
And make sure to register your new routes accordingly:
Route::get('photo/download', 'PhotoController#download')->name('photo.download');
Route::get('photo/fancybox', 'PhotoController#fancybox')->name('photo.fancybox');

How to use AJAX for GET requests in Totaljs?

I am using the below code. The AJAX GET is returning status code 500. I am not sure what is missing.
<div class="container pt-1" id="usersList">
<h5>List of Users</h5>
<div data-bind="users.list__template">
<ul class="list-group">
#{foreach user in model}
<a class="userList" href=/#{user._id}> <li class="list-group-item">#{user.name}</li></a>
#{end}
</ul>
</div>
</div>
$('#usersListLink').on('click', (event) => {
event.preventDefault();
AJAX('GET /usersList', 'items --> usersList.items');
$("#homepage").hide();
$("#usersList").show();
$("#addUser").hide();
});
It's hard to say just from what you shown.
But on the controllers check the route, it looks it could be flag with some role permits.
F.route('/uesrslist', get_platform, ['authorize', '#role']);
This could be different depending on how your project is created.

Thymeleaf display element as active when using layout

I wanted to display navigation element as active (class nav-item active) when that element is clicked and the other elements with the non active class (nav-item). I am also using Thymeleaf layouts.
In the controller i have following code
#GetMapping("/login")
public String getLoginPage(Model model) {
model.addAttribute("activeLink", "Login");
return "login";
}
In the layout.html file (this file contains common header and footer for all pages), i have following code
<nav th:replace="navigation.html :: navibar(activeLink=${activeLink})"></nav>
In the navigation.html (this file only has navigation related code), i have code similar to
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top" th:fragment="navibar(activeLink)">
<a class="navbar-brand" href="/title">Title</a>
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
<ul class="navbar-nav mr-auto">
<li th:class="${#strings.equals(activeLink, 'Home')} ? 'nav-item active' : 'nav-item'"><a class="nav-link" href="/">Home<span class="sr-only">(current)</span></a></li>
<li th:class="${#strings.equals(activeLink, 'Register')} ? 'nav-item active' : 'nav-item'"><a class="nav-link" href="/register">Register</a></li>
<li th:class="${#strings.equals(activeLink, 'Login')} ? 'nav-item active' : 'nav-item'" sec:authorize="isAnonymous()"><a class="nav-link" th:href="#{/login}">Login <span class="sr-only">(current)</span></a></li>
<li class="nav-item active" sec:authorize="isAuthenticated()"><a class="nav-link" th:href="#{/logout}">Logout <span class="sr-only">(current)</span></a></li>
</ul>
</div>
In the template returned by the controller (login), I do not have any navigation links specific code.
The above code is working, but is there a better simpler way to active navigation items?
Also, if I use flash attributes
redirectAttributes.addFlashAttribute("activeLink", "Register");
in the controller, then the functionality doesn't work
To avoid adding the activeLink to the model you can pass the activeLink when you include the fragment.
Like:
<div th:replace="nagivation :: navibar('Login')"></div>
Btw. you can remove the .html after the layout name.

How to set the login/logout link visible/invisible with Thymeleaf?

I am a beginner in Spring Framework. I try to make login and logout Thymeleaf pages. Below codes are the Spring Boot login/logout files with Thymeleaf.
First, Login Controllers codes
#Autowired
private HttpSession userSession;
#Autowired
private UserService userService;
#RequestMapping("/users/login")
public String login(LoginForm loginForm) {
return "users/login";
}
#RequestMapping(value="/users/login", method = RequestMethod.POST)
public String loginPage(#Valid LoginForm loginForm, BindingResult bindingResult) {
if(bindingResult.hasErrors()) {
userSession.setAttribute("blogLogin", false);
System.out.println("Wrong Input!!");
return "users/login";
}
if(!userService.authenticate(loginForm.getUsername(), loginForm.getPassword())) {
userSession.setAttribute("blogLogin", false);
System.out.println("login failed!!");
return "users/login";
}
userSession.setAttribute("blogLogin", true);
System.out.println("Login succesfully.");
return "redirect:/";
}
And the layout.html codes using thymeleaf.
<header th:fragment="site-header" th:remove="tag">
<header>
<a href="index.html" th:href="#{/}">
<img src="../public/img/site-logo.png" th:src="#{/img/site-logo.png}" />
</a>
Home
Log in
Log out
Register
Users
Posts
Write Post
<div id="logged-in-info"><span>Hello, <b>(user)</b></span>
<form method="post" th:action="#{/users/logout}">
<input type="submit" value="Log out"/>
</form>
</div>
</header>
</header>
The problem is I have no idea how to make login/logout link toggling codes using th:if statement of thymeleaf. As you know login link and logout link can not be displayed simultaneously.
you can check whether user is authenticated or anonymous like below and can make decisions.
<div sec:authorize="#{isAuthenticated()}">
<a th:href="#{/logout}">Log out</a>
</div>
<div sec:authorize="#{isAnonymous()}">
<a th:href="#{/login}">Log in</a>
</div>

Resources