Changed logins to have proper redirections
This commit is contained in:
parent
1bce01e07e
commit
20b9dcf1d5
@ -3,6 +3,7 @@ package uk.co.neviyn.booru
|
|||||||
import org.springframework.beans.factory.annotation.Autowired
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
import org.springframework.data.domain.Page
|
import org.springframework.data.domain.Page
|
||||||
import org.springframework.data.domain.PageRequest
|
import org.springframework.data.domain.PageRequest
|
||||||
|
import org.springframework.security.access.annotation.Secured
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal
|
import org.springframework.security.core.annotation.AuthenticationPrincipal
|
||||||
import org.springframework.stereotype.Controller
|
import org.springframework.stereotype.Controller
|
||||||
import org.springframework.ui.Model
|
import org.springframework.ui.Model
|
||||||
@ -33,13 +34,17 @@ class BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/login")
|
@GetMapping("/login")
|
||||||
fun login(model: Model, error: String?, logout: String?): String? {
|
fun login(model: Model, error: String?, logout: String?, @RequestParam redirect: String): String? {
|
||||||
if (error != null) model.addAttribute("error", "Your username and password is invalid.")
|
if (error != null) model.addAttribute("error", "Your username and password is invalid.")
|
||||||
if (logout != null) model.addAttribute("message", "You have been logged out successfully.")
|
if (logout != null) model.addAttribute("message", "You have been logged out successfully.")
|
||||||
|
model.addAttribute("redirect", redirect)
|
||||||
return "login"
|
return "login"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun userCanEdit(userDetails: CustomUserDetails?, image: Image): Boolean =
|
||||||
|
userDetails != null && (userDetails.authorities.any { it.authority == "ADMIN" } || userDetails.getId() == image.uploader.id)
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
@RequestMapping("/view/{id}")
|
@RequestMapping("/view/{id}")
|
||||||
class SingleImageViewController
|
class SingleImageViewController
|
||||||
@ -54,15 +59,41 @@ class SingleImageViewController
|
|||||||
model.addAttribute("image", image)
|
model.addAttribute("image", image)
|
||||||
model.addAttribute("tags", tagData)
|
model.addAttribute("tags", tagData)
|
||||||
model.addAttribute("title", tagData.joinToString { it.tag })
|
model.addAttribute("title", tagData.joinToString { it.tag })
|
||||||
model.addAttribute("isUploader", (userDetails != null && (userDetails.authorities.any { it.authority == "ADMIN" } || userDetails.getId() == image.uploader.id)))
|
model.addAttribute("isUploader", userCanEdit(userDetails, image))
|
||||||
return "single"
|
return "single"
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/removetag")
|
@PostMapping("/addtag")
|
||||||
|
@Secured
|
||||||
@Transactional
|
@Transactional
|
||||||
fun removeTagFromImage(@PathVariable id: Long, @RequestParam("tagId") tagID: Long, model: Model, @AuthenticationPrincipal userDetails: CustomUserDetails?) : String {
|
fun addTagToImage(
|
||||||
|
@PathVariable id: Long,
|
||||||
|
@RequestParam("tagName") tagName: String,
|
||||||
|
model: Model,
|
||||||
|
@AuthenticationPrincipal userDetails: CustomUserDetails?
|
||||||
|
): String {
|
||||||
val image = imageRepository.findById(id).get()
|
val image = imageRepository.findById(id).get()
|
||||||
if(userDetails == null || userDetails.getId() != image.uploader.id || !userDetails.authorities.any { it.authority == "ADMIN" }) return "redirect:/view/$id"
|
if (!userCanEdit(userDetails, image)) return "redirect:/view/$id"
|
||||||
|
var newTag = tagRepository.findByTagIs(tagName) ?: Tag(tag = tagName)
|
||||||
|
if (image.tags.contains(newTag)) return "redirect:/view/$id" // Don't add a tag that an image already has
|
||||||
|
newTag.amount += 1
|
||||||
|
newTag = tagRepository.save(newTag)
|
||||||
|
image.tags.add(newTag)
|
||||||
|
imageRepository.save(image)
|
||||||
|
return "redirect:/view/$id"
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/removetag")
|
||||||
|
@Secured
|
||||||
|
@Transactional
|
||||||
|
fun removeTagFromImage(
|
||||||
|
@PathVariable id: Long,
|
||||||
|
@RequestParam("tagId") tagID: Long,
|
||||||
|
model: Model,
|
||||||
|
@AuthenticationPrincipal userDetails: CustomUserDetails?
|
||||||
|
): String {
|
||||||
|
val image = imageRepository.findById(id).get()
|
||||||
|
if (!userCanEdit(userDetails, image)) return "redirect:/view/$id"
|
||||||
val targetTag = image.tags.find { it.id == tagID }
|
val targetTag = image.tags.find { it.id == tagID }
|
||||||
if (targetTag != null) {
|
if (targetTag != null) {
|
||||||
targetTag.amount -= 1
|
targetTag.amount -= 1
|
||||||
@ -127,13 +158,15 @@ class MemberController
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
@GetMapping
|
@GetMapping
|
||||||
fun memberDetails(@AuthenticationPrincipal userDetails: CustomUserDetails, model: Model) : String {
|
fun memberDetails(@AuthenticationPrincipal userDetails: CustomUserDetails?, model: Model): String {
|
||||||
|
if (userDetails == null) return "redirect:/login?redirect=/user"
|
||||||
val user = DisplayUser(userDetails.getId(), userDetails.username, userDetails.getEmail(), "", "")
|
val user = DisplayUser(userDetails.getId(), userDetails.username, userDetails.getEmail(), "", "")
|
||||||
model.addAttribute("userData", user)
|
model.addAttribute("userData", user)
|
||||||
return "user"
|
return "user"
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping
|
@PostMapping
|
||||||
|
@Secured
|
||||||
fun updateLoggedInUser(@Valid @ModelAttribute userData: DisplayUser, @AuthenticationPrincipal userDetails: CustomUserDetails, model: Model): String {
|
fun updateLoggedInUser(@Valid @ModelAttribute userData: DisplayUser, @AuthenticationPrincipal userDetails: CustomUserDetails, model: Model): String {
|
||||||
if (userData.id == userDetails.getId() && passwordEncoder().matches(userData.oldPassword, userDetails.password)) {
|
if (userData.id == userDetails.getId() && passwordEncoder().matches(userData.oldPassword, userDetails.password)) {
|
||||||
val user = memberRepository.findById(userDetails.getId()).get()
|
val user = memberRepository.findById(userDetails.getId()).get()
|
||||||
@ -162,9 +195,13 @@ class UploadController
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
@GetMapping
|
@GetMapping
|
||||||
fun showUploadPage(): String = "upload"
|
fun showUploadPage(@AuthenticationPrincipal userDetails: CustomUserDetails?): String {
|
||||||
|
if (userDetails == null) return "redirect:/login?redirect=/upload"
|
||||||
|
return "upload"
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping
|
@PostMapping
|
||||||
|
@Secured
|
||||||
fun uploadFile(
|
fun uploadFile(
|
||||||
@AuthenticationPrincipal userDetails: CustomUserDetails,
|
@AuthenticationPrincipal userDetails: CustomUserDetails,
|
||||||
@RequestParam file: MultipartFile,
|
@RequestParam file: MultipartFile,
|
||||||
@ -183,6 +220,7 @@ class UploadController
|
|||||||
}
|
}
|
||||||
|
|
||||||
@DeleteMapping("/d/{imageID}")
|
@DeleteMapping("/d/{imageID}")
|
||||||
|
@Secured
|
||||||
@Transactional
|
@Transactional
|
||||||
fun deleteUpload(@PathVariable imageID: Long, @AuthenticationPrincipal userDetails: CustomUserDetails): String {
|
fun deleteUpload(@PathVariable imageID: Long, @AuthenticationPrincipal userDetails: CustomUserDetails): String {
|
||||||
val target = imageRepository.findById(imageID)
|
val target = imageRepository.findById(imageID)
|
||||||
|
@ -13,7 +13,12 @@ import org.springframework.security.core.userdetails.UserDetailsService
|
|||||||
import org.springframework.security.core.userdetails.UsernameNotFoundException
|
import org.springframework.security.core.userdetails.UsernameNotFoundException
|
||||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder
|
import org.springframework.security.crypto.password.PasswordEncoder
|
||||||
|
import org.springframework.security.web.authentication.AuthenticationSuccessHandler
|
||||||
|
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
import javax.servlet.http.HttpServletRequest
|
||||||
|
import javax.servlet.http.HttpServletResponse
|
||||||
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
class SecurityConfig
|
class SecurityConfig
|
||||||
@ -21,9 +26,9 @@ class SecurityConfig
|
|||||||
val userDetailsService: CustomUserDetailsService
|
val userDetailsService: CustomUserDetailsService
|
||||||
) : WebSecurityConfigurerAdapter() {
|
) : WebSecurityConfigurerAdapter() {
|
||||||
override fun configure(http: HttpSecurity) {
|
override fun configure(http: HttpSecurity) {
|
||||||
http.authorizeRequests().antMatchers("/upload/**", "/user/**").hasAuthority("USER")
|
http.authorizeRequests()
|
||||||
.anyRequest().permitAll().and()
|
.anyRequest().permitAll().and()
|
||||||
.formLogin().loginPage("/login").permitAll().and()
|
.formLogin().successHandler(RefererRedirectionAuthenticationSuccessHandler()).loginPage("/login").permitAll().and()
|
||||||
.logout().logoutSuccessUrl("/").permitAll().and()
|
.logout().logoutSuccessUrl("/").permitAll().and()
|
||||||
.httpBasic()
|
.httpBasic()
|
||||||
}
|
}
|
||||||
@ -66,3 +71,11 @@ class CustomUserDetailsService
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
fun passwordEncoder(): PasswordEncoder = BCryptPasswordEncoder()
|
fun passwordEncoder(): PasswordEncoder = BCryptPasswordEncoder()
|
||||||
|
|
||||||
|
// Keeps us on the same page when logging in
|
||||||
|
class RefererRedirectionAuthenticationSuccessHandler : SimpleUrlAuthenticationSuccessHandler(), AuthenticationSuccessHandler {
|
||||||
|
|
||||||
|
override fun determineTargetUrl(request: HttpServletRequest?, response: HttpServletResponse?): String {
|
||||||
|
return request!!.getParameter("redirect")
|
||||||
|
}
|
||||||
|
}
|
@ -1,14 +1,14 @@
|
|||||||
<!DOCTYPE HTML>
|
<!DOCTYPE HTML>
|
||||||
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
|
<html lang="en" xmlns:sec="http://www.thymeleaf.org/extras/spring-security" xmlns:th="http://www.thymeleaf.org">
|
||||||
<body>
|
<body>
|
||||||
<div th:fragment="header" th:remove="tag">
|
<div th:fragment="header" th:remove="tag">
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<!-- Favicon -->
|
<!-- Favicon -->
|
||||||
<link rel="icon" type="image/svg+xml" th:href="@{/webjars/bootstrap-icons/1.4.1/icons/images.svg}">
|
<link rel="icon" th:href="@{/webjars/bootstrap-icons/1.4.1/icons/images.svg}" type="image/svg+xml">
|
||||||
<!-- Common styles and scripts -->
|
<!-- Common styles and scripts -->
|
||||||
<link th:href="@{/webjars/bootstrap/5.0.0-beta3/css/bootstrap.min.css}" rel="stylesheet">
|
<link rel="stylesheet" th:href="@{/webjars/bootstrap/5.0.0-beta3/css/bootstrap.min.css}">
|
||||||
<script th:src="@{/webjars/bootstrap/5.0.0-beta3/js/bootstrap.bundle.min.js}"></script>
|
<script th:src="@{/webjars/bootstrap/5.0.0-beta3/js/bootstrap.bundle.min.js}"></script>
|
||||||
<link th:href="@{/webjars/bootstrap-icons/1.4.1/font/bootstrap-icons.css}" rel="stylesheet">
|
<link rel="stylesheet" th:href="@{/webjars/bootstrap-icons/1.4.1/font/bootstrap-icons.css}">
|
||||||
</div>
|
</div>
|
||||||
<div th:fragment="navbar">
|
<div th:fragment="navbar">
|
||||||
<form id="logoutForm" method="POST" th:action="@{/logout}">
|
<form id="logoutForm" method="POST" th:action="@{/logout}">
|
||||||
@ -29,13 +29,28 @@
|
|||||||
<a class="nav-link" th:href="${#mvc.url('UC#showUploadPage').build()}">Upload</a>
|
<a class="nav-link" th:href="${#mvc.url('UC#showUploadPage').build()}">Upload</a>
|
||||||
<a class="nav-link" th:href="${#mvc.url('MC#memberDetails').build()}">My Account</a>
|
<a class="nav-link" th:href="${#mvc.url('MC#memberDetails').build()}">My Account</a>
|
||||||
</div>
|
</div>
|
||||||
<div sec:authorize="isAuthenticated()" class="d-flex">
|
<div class="d-flex" sec:authorize="isAuthenticated()">
|
||||||
<span sec:authentication="name" class="navbar-text"></span>
|
<span class="navbar-text" sec:authentication="name"></span>
|
||||||
<a class="nav-link" onclick="document.forms['logoutForm'].submit()" style="cursor: pointer"><i
|
<a class="nav-link" onclick="document.forms['logoutForm'].submit()" style="cursor: pointer"><i
|
||||||
class="bi bi-box-arrow-right me-1"></i>Logout</a>
|
class="bi bi-box-arrow-right me-1"></i>Logout</a>
|
||||||
</div>
|
</div>
|
||||||
|
<form class="form-sign_in" method="POST" sec:authorize="!isAuthenticated()" th:action="@{/login}">
|
||||||
|
<div class="form-group d-flex flex-row align-items-center">
|
||||||
|
<input id="redirectURL" name="redirect" type="hidden" value="">
|
||||||
|
<!--suppress HtmlFormInputWithoutLabel -->
|
||||||
|
<input class="form-control form-control-sm" id="username" name="username" placeholder="Username" type="text">
|
||||||
|
<!--suppress HtmlFormInputWithoutLabel -->
|
||||||
|
<input class="form-control form-control-sm" id="password" name="password" placeholder="Password" type="password">
|
||||||
|
<input name="${_csrf.parameterName}" type="hidden" value="${_csrf.token}"/>
|
||||||
|
<button class="btn btn-primary btn-sm text-nowrap" type="submit">Log In</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<script>
|
||||||
|
// Set logging in via this page to redirect back to this exact page
|
||||||
|
document.getElementById('redirectURL').setAttribute('value', window.location.href)
|
||||||
|
</script>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
<div th:fragment="searchBarRow">
|
<div th:fragment="searchBarRow">
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
<div class="col-8 text-center">
|
<div class="col-8 text-center">
|
||||||
<form class="form-sign_in" method="POST" th:action="@{/login}">
|
<form class="form-sign_in" method="POST" th:action="@{/login}">
|
||||||
<div class="form-group mt-3">
|
<div class="form-group mt-3">
|
||||||
|
<input name="redirect" th:value="${redirect}" type="hidden">
|
||||||
<span th:text="${message}"></span>
|
<span th:text="${message}"></span>
|
||||||
<div class="form-floating mb-3">
|
<div class="form-floating mb-3">
|
||||||
<input autofocus class="form-control form-control-lg" id="username" name="username" type="text">
|
<input autofocus class="form-control form-control-lg" id="username" name="username" type="text">
|
||||||
@ -39,7 +40,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="row justify-content-center mt-3">
|
<div class="row justify-content-center mt-3">
|
||||||
<div class="col text-center">
|
<div class="col text-center">
|
||||||
<a class="btn btn-secondary btn-lg" th:href="${#mvc.url('BC#landingPage').build()}" role="button">Home</a>
|
<a class="btn btn-secondary btn-lg" role="button" th:href="${#mvc.url('BC#landingPage').build()}">Home</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -15,13 +15,18 @@
|
|||||||
<a class="text-decoration-none"
|
<a class="text-decoration-none"
|
||||||
th:href="${#mvc.url('IC#getGalleryPage').arg(1, tag.tag).build()}"
|
th:href="${#mvc.url('IC#getGalleryPage').arg(1, tag.tag).build()}"
|
||||||
th:text="${tag.tag} + ' '">tag</a><span th:text="${tag.amount}"></span>
|
th:text="${tag.tag} + ' '">tag</a><span th:text="${tag.amount}"></span>
|
||||||
<form th:action="${'/view/' + image.id + '/removetag'}" method="post" th:if="${isUploader}">
|
<form method="post" th:action="${'/view/' + image.id + '/removetag'}" th:if="${isUploader}">
|
||||||
<input type="hidden" th:value="${tag.id}" name="tagId">
|
<input name="tagId" th:value="${tag.id}" type="hidden">
|
||||||
<button type="submit">-</button>
|
<button type="submit">-</button>
|
||||||
</form>
|
</form>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>Uploaded by: <span th:text="${image.uploader.name}"></span></p>
|
<p>Uploaded by: <span th:text="${image.uploader.name}"></span></p>
|
||||||
|
<form method="post" th:action="'/view/' + ${image.id} + '/addtag'" th:if="${isUploader}">
|
||||||
|
<!--suppress HtmlFormInputWithoutLabel -->
|
||||||
|
<input name="tagName" placeholder="Add a new tag" type="text">
|
||||||
|
<button type="submit">+</button>
|
||||||
|
</form>
|
||||||
<form th:action="'/upload/d/' + ${image.id}"
|
<form th:action="'/upload/d/' + ${image.id}"
|
||||||
th:if="${isUploader}"
|
th:if="${isUploader}"
|
||||||
th:method="delete">
|
th:method="delete">
|
||||||
|
Loading…
Reference in New Issue
Block a user