Reflect grouping in directory structure
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
package com.example.security.thymeleaf;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.aot.smoketest.support.junit.ApplicationTest;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@ApplicationTest
|
||||
public class SecurityThymeleafApplicationAotTests {
|
||||
|
||||
@Test
|
||||
void helloShouldBeProtectedWithNoCredentials(WebTestClient client) {
|
||||
client.get().uri("/hello").exchange().expectStatus().isUnauthorized();
|
||||
}
|
||||
|
||||
@Test
|
||||
void homeShouldNotBeProtectedWithNoCredentials(WebTestClient client) {
|
||||
client.get().uri("/").exchange().expectStatus().isOk().expectBody()
|
||||
.consumeWith((result) -> assertThat(new String(result.getResponseBodyContent()))
|
||||
.contains("Click <a href=\"/hello\">here</a> to see a greeting."));
|
||||
}
|
||||
|
||||
@Test
|
||||
void helloShouldShowUsernameWithRoleUser(WebTestClient client) {
|
||||
client.get().uri("/hello").headers((header) -> header.setBasicAuth("user", "password")).exchange()
|
||||
.expectStatus().isOk().expectBody()
|
||||
.consumeWith((result) -> assertThat(new String(result.getResponseBodyContent()))
|
||||
.contains("Hello <span>user</span>").contains("Logged in user: <span>user</span>")
|
||||
.contains("Roles: <span>[ROLE_USER]</span>"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void helloShouldNotShowUsernameWithRoleAdmin(WebTestClient client) {
|
||||
client.get().uri("/hello").headers((header) -> header.setBasicAuth("admin", "password")).exchange()
|
||||
.expectStatus().isOk().expectBody()
|
||||
.consumeWith((result) -> assertThat(new String(result.getResponseBodyContent()))
|
||||
.doesNotContain("Hello <span>admin</span>").contains("Logged in user: <span>admin</span>")
|
||||
.contains("Roles: <span>[ROLE_ADMIN]</span>"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.example.security.thymeleaf;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
@Controller
|
||||
public class MainController {
|
||||
|
||||
@GetMapping("/")
|
||||
public String index() {
|
||||
return "home";
|
||||
}
|
||||
|
||||
@GetMapping("/hello")
|
||||
public String hello() {
|
||||
return "hello";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.example.security.thymeleaf;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
|
||||
import static org.springframework.security.config.Customizer.withDefaults;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
public class SecurityConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
return http
|
||||
.authorizeHttpRequests(
|
||||
(authorize) -> authorize.requestMatchers("/").permitAll().anyRequest().authenticated())
|
||||
.httpBasic(withDefaults()).formLogin(withDefaults()).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@SuppressWarnings("deprecation")
|
||||
UserDetailsService userDetailsService() {
|
||||
UserDetails user = User.withDefaultPasswordEncoder().username("user").password("password").roles("USER")
|
||||
.build();
|
||||
UserDetails admin = User.withDefaultPasswordEncoder().username("admin").password("password").roles("ADMIN")
|
||||
.build();
|
||||
|
||||
return new InMemoryUserDetailsManager(user, admin);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.example.security.thymeleaf;
|
||||
|
||||
import org.springframework.aot.hint.MemberCategory;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.RuntimeHintsRegistrar;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.ImportRuntimeHints;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
|
||||
@SpringBootApplication
|
||||
@ImportRuntimeHints(SecurityThymeleafApplication.Hints.class)
|
||||
public class SecurityThymeleafApplication {
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
SpringApplication.run(SecurityThymeleafApplication.class, args);
|
||||
Thread.currentThread().join(); // To be able to measure memory consumption
|
||||
}
|
||||
|
||||
static class Hints implements RuntimeHintsRegistrar {
|
||||
|
||||
@Override
|
||||
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
|
||||
hints.reflection().registerType(UsernamePasswordAuthenticationToken.class,
|
||||
MemberCategory.INVOKE_PUBLIC_METHODS);
|
||||
hints.reflection().registerType(User.class, MemberCategory.INVOKE_PUBLIC_METHODS);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org"
|
||||
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
|
||||
<head>
|
||||
<title>Hello</title>
|
||||
</head>
|
||||
<body>
|
||||
<div sec:authorize="hasRole('ROLE_USER')">
|
||||
Hello <span th:text="${#authentication.name}"></span>!
|
||||
</div>
|
||||
<div sec:authorize="isAuthenticated()">
|
||||
Logged in user: <span sec:authentication="name"></span> |
|
||||
Roles: <span sec:authentication="principal.authorities"></span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org">
|
||||
<head>
|
||||
<title>Spring Security Thymeleaf Example</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Welcome!</h1>
|
||||
|
||||
<p>Click <a th:href="@{/hello}">here</a> to see a greeting.</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.example.security.thymeleaf;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.security.test.context.support.WithMockUser;
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.FormLoginRequestBuilder;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
|
||||
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
|
||||
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.unauthenticated;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@SpringBootTest
|
||||
@AutoConfigureMockMvc
|
||||
public class SecurityThymeleafApplicationTests {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Test
|
||||
public void loginWithValidUserThenAuthenticated() throws Exception {
|
||||
FormLoginRequestBuilder login = formLogin().user("user").password("password");
|
||||
|
||||
mockMvc.perform(login).andExpect(authenticated().withUsername("user"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loginWithInvalidUserThenUnauthenticated() throws Exception {
|
||||
FormLoginRequestBuilder login = formLogin().user("invalid").password("invalidpassword");
|
||||
|
||||
mockMvc.perform(login).andExpect(unauthenticated());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accessUnsecuredResourceThenOk() throws Exception {
|
||||
mockMvc.perform(get("/")).andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accessSecuredResourceUnauthenticatedThenRedirectsToLogin() throws Exception {
|
||||
mockMvc.perform(get("/hello")).andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser
|
||||
public void accessSecuredResourceAuthenticatedThenOk() throws Exception {
|
||||
mockMvc.perform(get("/hello")).andExpect(status().isOk());
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user