15 changed files with 509 additions and 2 deletions
@ -0,0 +1,5 @@ |
|||||||
|
apply plugin: 'spring-boot' |
||||||
|
|
||||||
|
sonarqube { |
||||||
|
skipProject = true |
||||||
|
} |
||||||
@ -0,0 +1,16 @@ |
|||||||
|
apply from: BOOT_SAMPLE_GRADLE |
||||||
|
|
||||||
|
springBoot { |
||||||
|
mainClass = 'org.springframework.security.samples.HelloWorldApplication' |
||||||
|
} |
||||||
|
|
||||||
|
dependencies { |
||||||
|
compile "org.springframework.boot:spring-boot-starter-web", |
||||||
|
"org.springframework.boot:spring-boot-starter-thymeleaf", |
||||||
|
"org.thymeleaf.extras:thymeleaf-extras-springsecurity4:2.1.2.RELEASE", |
||||||
|
project(":spring-security-config"), |
||||||
|
project(":spring-security-web") |
||||||
|
|
||||||
|
testCompile "org.springframework.boot:spring-boot-starter-test", |
||||||
|
project(":spring-security-test") |
||||||
|
} |
||||||
@ -0,0 +1,144 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |
||||||
|
<modelVersion>4.0.0</modelVersion> |
||||||
|
<groupId>org.springframework.security</groupId> |
||||||
|
<artifactId>spring-security-samples-boot-helloworld</artifactId> |
||||||
|
<version>4.1.0.BUILD-SNAPSHOT</version> |
||||||
|
<name>spring-security-samples-boot-helloworld</name> |
||||||
|
<description>spring-security-samples-boot-helloworld</description> |
||||||
|
<url>http://spring.io/spring-security</url> |
||||||
|
<organization> |
||||||
|
<name>spring.io</name> |
||||||
|
<url>http://spring.io/</url> |
||||||
|
</organization> |
||||||
|
<licenses> |
||||||
|
<license> |
||||||
|
<name>The Apache Software License, Version 2.0</name> |
||||||
|
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url> |
||||||
|
<distribution>repo</distribution> |
||||||
|
</license> |
||||||
|
</licenses> |
||||||
|
<developers> |
||||||
|
<developer> |
||||||
|
<id>rwinch</id> |
||||||
|
<name>Rob Winch</name> |
||||||
|
<email>rwinch@gopivotal.com</email> |
||||||
|
</developer> |
||||||
|
</developers> |
||||||
|
<scm> |
||||||
|
<connection>scm:git:git://github.com/spring-projects/spring-security</connection> |
||||||
|
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection> |
||||||
|
<url>https://github.com/spring-projects/spring-security</url> |
||||||
|
</scm> |
||||||
|
<dependencyManagement> |
||||||
|
<dependencies> |
||||||
|
<dependency> |
||||||
|
<groupId>org.springframework</groupId> |
||||||
|
<artifactId>spring-framework-bom</artifactId> |
||||||
|
<version>4.2.5.RELEASE</version> |
||||||
|
<type>pom</type> |
||||||
|
<scope>import</scope> |
||||||
|
</dependency> |
||||||
|
</dependencies> |
||||||
|
</dependencyManagement> |
||||||
|
<dependencies> |
||||||
|
<dependency> |
||||||
|
<groupId>org.springframework.boot</groupId> |
||||||
|
<artifactId>spring-boot-starter-thymeleaf</artifactId> |
||||||
|
<scope>compile</scope> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>org.springframework.boot</groupId> |
||||||
|
<artifactId>spring-boot-starter-web</artifactId> |
||||||
|
<scope>compile</scope> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>org.springframework.security</groupId> |
||||||
|
<artifactId>spring-security-config</artifactId> |
||||||
|
<version>4.1.0.BUILD-SNAPSHOT</version> |
||||||
|
<scope>compile</scope> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>org.springframework.security</groupId> |
||||||
|
<artifactId>spring-security-web</artifactId> |
||||||
|
<version>4.1.0.BUILD-SNAPSHOT</version> |
||||||
|
<scope>compile</scope> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>org.thymeleaf.extras</groupId> |
||||||
|
<artifactId>thymeleaf-extras-springsecurity4</artifactId> |
||||||
|
<version>2.1.2.RELEASE</version> |
||||||
|
<scope>compile</scope> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>commons-logging</groupId> |
||||||
|
<artifactId>commons-logging</artifactId> |
||||||
|
<version>1.2</version> |
||||||
|
<scope>compile</scope> |
||||||
|
<optional>true</optional> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>ch.qos.logback</groupId> |
||||||
|
<artifactId>logback-classic</artifactId> |
||||||
|
<version>1.1.2</version> |
||||||
|
<scope>test</scope> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>junit</groupId> |
||||||
|
<artifactId>junit</artifactId> |
||||||
|
<version>4.12</version> |
||||||
|
<scope>test</scope> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>org.assertj</groupId> |
||||||
|
<artifactId>assertj-core</artifactId> |
||||||
|
<version>2.2.0</version> |
||||||
|
<scope>test</scope> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>org.mockito</groupId> |
||||||
|
<artifactId>mockito-core</artifactId> |
||||||
|
<version>1.10.19</version> |
||||||
|
<scope>test</scope> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>org.slf4j</groupId> |
||||||
|
<artifactId>jcl-over-slf4j</artifactId> |
||||||
|
<version>1.7.7</version> |
||||||
|
<scope>test</scope> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>org.springframework.boot</groupId> |
||||||
|
<artifactId>spring-boot-starter-test</artifactId> |
||||||
|
<scope>test</scope> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>org.springframework.security</groupId> |
||||||
|
<artifactId>spring-security-test</artifactId> |
||||||
|
<version>4.1.0.BUILD-SNAPSHOT</version> |
||||||
|
<scope>test</scope> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>org.springframework</groupId> |
||||||
|
<artifactId>spring-test</artifactId> |
||||||
|
<scope>test</scope> |
||||||
|
</dependency> |
||||||
|
</dependencies> |
||||||
|
<repositories> |
||||||
|
<repository> |
||||||
|
<id>spring-snapshot</id> |
||||||
|
<url>https://repo.spring.io/snapshot</url> |
||||||
|
</repository> |
||||||
|
</repositories> |
||||||
|
<build> |
||||||
|
<plugins> |
||||||
|
<plugin> |
||||||
|
<artifactId>maven-compiler-plugin</artifactId> |
||||||
|
<configuration> |
||||||
|
<source>1.7</source> |
||||||
|
<target>1.7</target> |
||||||
|
</configuration> |
||||||
|
</plugin> |
||||||
|
</plugins> |
||||||
|
</build> |
||||||
|
</project> |
||||||
@ -0,0 +1,120 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2012-2016 the original author or authors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
package org.springframework.security.samples; |
||||||
|
|
||||||
|
import org.junit.Before; |
||||||
|
import org.junit.Test; |
||||||
|
import org.junit.runner.RunWith; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.boot.test.SpringApplicationConfiguration; |
||||||
|
import org.springframework.mock.web.MockHttpSession; |
||||||
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; |
||||||
|
import org.springframework.test.context.web.WebAppConfiguration; |
||||||
|
import org.springframework.test.web.servlet.MockMvc; |
||||||
|
import org.springframework.test.web.servlet.MvcResult; |
||||||
|
import org.springframework.test.web.servlet.setup.MockMvcBuilders; |
||||||
|
import org.springframework.web.context.WebApplicationContext; |
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||||
|
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin; |
||||||
|
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; |
||||||
|
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.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; |
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; |
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; |
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author Joe Grandja |
||||||
|
*/ |
||||||
|
@RunWith(SpringJUnit4ClassRunner.class) |
||||||
|
@SpringApplicationConfiguration(HelloWorldApplication.class) |
||||||
|
@WebAppConfiguration |
||||||
|
public class HelloWorldApplicationTests { |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private WebApplicationContext context; |
||||||
|
|
||||||
|
private MockMvc mockMvc; |
||||||
|
|
||||||
|
@Before |
||||||
|
public void setup() { |
||||||
|
mockMvc = MockMvcBuilders |
||||||
|
.webAppContextSetup(context) |
||||||
|
.apply(springSecurity()) |
||||||
|
.build(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void accessUnprotected() throws Exception { |
||||||
|
this.mockMvc.perform(get("/index")).andExpect(status().isOk()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void accessProtectedRedirectsToLogin() throws Exception { |
||||||
|
MvcResult mvcResult = this.mockMvc.perform(get("/user/index")) |
||||||
|
.andExpect(status().is3xxRedirection()) |
||||||
|
.andReturn(); |
||||||
|
|
||||||
|
assertThat(mvcResult.getResponse().getRedirectedUrl()).endsWith("/login"); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void loginUser() throws Exception { |
||||||
|
this.mockMvc.perform(formLogin().user("user1").password("password1")) |
||||||
|
.andExpect(authenticated()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void loginInvalidUser() throws Exception { |
||||||
|
this.mockMvc.perform(formLogin().user("invalid").password("invalid")) |
||||||
|
.andExpect(unauthenticated()) |
||||||
|
.andExpect(status().is3xxRedirection()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void loginUserAccessProtected() throws Exception { |
||||||
|
MvcResult mvcResult = this.mockMvc.perform(formLogin().user("user1").password("password1")) |
||||||
|
.andExpect(authenticated()) |
||||||
|
.andReturn(); |
||||||
|
|
||||||
|
MockHttpSession httpSession = MockHttpSession.class.cast(mvcResult.getRequest().getSession(false)); |
||||||
|
|
||||||
|
this.mockMvc.perform(get("/user/index") |
||||||
|
.session(httpSession)) |
||||||
|
.andExpect(status().isOk()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void loginUserValidateLogout() throws Exception { |
||||||
|
MvcResult mvcResult = this.mockMvc.perform(formLogin().user("user1").password("password1")) |
||||||
|
.andExpect(authenticated()) |
||||||
|
.andReturn(); |
||||||
|
|
||||||
|
MockHttpSession httpSession = MockHttpSession.class.cast(mvcResult.getRequest().getSession(false)); |
||||||
|
|
||||||
|
this.mockMvc.perform(post("/logout").with(csrf()) |
||||||
|
.session(httpSession)) |
||||||
|
.andExpect(unauthenticated()); |
||||||
|
|
||||||
|
this.mockMvc.perform(get("/user/index") |
||||||
|
.session(httpSession)) |
||||||
|
.andExpect(unauthenticated()) |
||||||
|
.andExpect(status().is3xxRedirection()); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,32 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2012-2016 the original author or authors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
package org.springframework.security.samples; |
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication; |
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Joe Grandja |
||||||
|
*/ |
||||||
|
@SpringBootApplication |
||||||
|
public class HelloWorldApplication { |
||||||
|
|
||||||
|
public static void main(String[] args) { |
||||||
|
SpringApplication.run(HelloWorldApplication.class, args); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,50 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2016 the original author or authors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
package org.springframework.security.samples.config; |
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; |
||||||
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity; |
||||||
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; |
||||||
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Joe Grandja |
||||||
|
*/ |
||||||
|
@EnableWebSecurity |
||||||
|
public class SecurityConfig extends WebSecurityConfigurerAdapter { |
||||||
|
|
||||||
|
// @formatter:off
|
||||||
|
@Override |
||||||
|
protected void configure(HttpSecurity http) throws Exception { |
||||||
|
http |
||||||
|
.authorizeRequests() |
||||||
|
.antMatchers("/css/**", "/index").permitAll() |
||||||
|
.antMatchers("/user/**").hasRole("USER") |
||||||
|
.and() |
||||||
|
.formLogin().loginPage("/login").failureUrl("/login-error"); |
||||||
|
} |
||||||
|
// @formatter:on
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
|
@Autowired |
||||||
|
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { |
||||||
|
auth |
||||||
|
.inMemoryAuthentication() |
||||||
|
.withUser("user1").password("password1").roles("USER"); |
||||||
|
} |
||||||
|
// @formatter:on
|
||||||
|
} |
||||||
@ -0,0 +1,54 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2016 the original author or authors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
package org.springframework.security.samples.web; |
||||||
|
|
||||||
|
import org.springframework.stereotype.Controller; |
||||||
|
import org.springframework.ui.Model; |
||||||
|
import org.springframework.web.bind.annotation.RequestMapping; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Joe Grandja |
||||||
|
*/ |
||||||
|
@Controller |
||||||
|
public class MainController { |
||||||
|
|
||||||
|
@RequestMapping("/") |
||||||
|
public String root() { |
||||||
|
return "redirect:/index"; |
||||||
|
} |
||||||
|
|
||||||
|
@RequestMapping("/index") |
||||||
|
public String index() { |
||||||
|
return "index"; |
||||||
|
} |
||||||
|
|
||||||
|
@RequestMapping("/user/index") |
||||||
|
public String userIndex() { |
||||||
|
return "user/index"; |
||||||
|
} |
||||||
|
|
||||||
|
@RequestMapping("/login") |
||||||
|
public String login() { |
||||||
|
return "login"; |
||||||
|
} |
||||||
|
|
||||||
|
@RequestMapping("/login-error") |
||||||
|
public String loginError(Model model) { |
||||||
|
model.addAttribute("loginError", true); |
||||||
|
return "login"; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,12 @@ |
|||||||
|
server: |
||||||
|
port: 8080 |
||||||
|
|
||||||
|
logging: |
||||||
|
level: |
||||||
|
root: WARN |
||||||
|
org.springframework.web: INFO |
||||||
|
org.springframework.security: INFO |
||||||
|
|
||||||
|
spring: |
||||||
|
thymeleaf: |
||||||
|
cache: true |
||||||
@ -0,0 +1,13 @@ |
|||||||
|
body { |
||||||
|
font-family: sans; |
||||||
|
font-size: 1em; |
||||||
|
} |
||||||
|
|
||||||
|
p.error { |
||||||
|
font-weight: bold; |
||||||
|
color: red; |
||||||
|
} |
||||||
|
|
||||||
|
div.logout { |
||||||
|
float: right; |
||||||
|
} |
||||||
@ -0,0 +1,25 @@ |
|||||||
|
<!DOCTYPE html> |
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4"> |
||||||
|
<head> |
||||||
|
<title>Hello Spring Security</title> |
||||||
|
<meta charset="utf-8" /> |
||||||
|
<link rel="stylesheet" href="/css/main.css" th:href="@{/css/main.css}" /> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
<div th:fragment="logout" class="logout" sec:authorize="isAuthenticated()"> |
||||||
|
Logged in user: <span sec:authentication="name"></span> | |
||||||
|
Roles: <span sec:authentication="principal.authorities"></span> |
||||||
|
<div> |
||||||
|
<form action="/logout" method="post"> |
||||||
|
<input type="submit" value="Logout" /> |
||||||
|
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" /> |
||||||
|
</form> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<h1>Hello Spring Security</h1> |
||||||
|
<p>This is an unsecured page, but you can access the secured pages after authenticating.</p> |
||||||
|
<ul> |
||||||
|
<li>Go to the <a href="/user/index" th:href="@{/user/index}">secured pages</a></li> |
||||||
|
</ul> |
||||||
|
</body> |
||||||
|
</html> |
||||||
@ -0,0 +1,21 @@ |
|||||||
|
<!DOCTYPE html> |
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> |
||||||
|
<head> |
||||||
|
<title>Login page</title> |
||||||
|
<meta charset="utf-8" /> |
||||||
|
<link rel="stylesheet" href="/css/main.css" th:href="@{/css/main.css}" /> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
<h1>Login page</h1> |
||||||
|
<p>Example user: user1 / password1</p> |
||||||
|
<p th:if="${loginError}" class="error">Wrong user or password</p> |
||||||
|
<form th:action="@{/login}" method="post"> |
||||||
|
<label for="username">Username</label>: |
||||||
|
<input type="text" id="username" name="username" autofocus="autofocus" /> <br /> |
||||||
|
<label for="password">Password</label>: |
||||||
|
<input type="password" id="password" name="password" /> <br /> |
||||||
|
<input type="submit" value="Log in" /> |
||||||
|
</form> |
||||||
|
<p><a href="/index" th:href="@{/index}">Back to home page</a></p> |
||||||
|
</body> |
||||||
|
</html> |
||||||
@ -0,0 +1,13 @@ |
|||||||
|
<!DOCTYPE html> |
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> |
||||||
|
<head> |
||||||
|
<title>Hello Spring Security</title> |
||||||
|
<meta charset="utf-8" /> |
||||||
|
<link rel="stylesheet" href="/css/main.css" th:href="@{/css/main.css}" /> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
<div th:substituteby="index::logout"></div> |
||||||
|
<h1>This is a secured page!</h1> |
||||||
|
<p><a href="/index" th:href="@{/index}">Back to home page</a></p> |
||||||
|
</body> |
||||||
|
</html> |
||||||
Loading…
Reference in new issue