提交 2aa9a110 编写于 作者: alvachien's avatar alvachien

Try to make the auth server completed

上级 ec75c88a
......@@ -48,7 +48,6 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
......
......@@ -16,7 +16,6 @@ import com.poc.alvachien.authserverdemo.model.UserRole;
import com.poc.alvachien.authserverdemo.repository.UserAccountRepository;
import com.poc.alvachien.authserverdemo.repository.UserRoleRepository;
import java.util.Arrays;
import java.util.UUID;
import org.slf4j.Logger;
......
......@@ -37,6 +37,7 @@ import org.springframework.security.oauth2.server.authorization.token.JwtEncodin
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices;
import org.springframework.security.crypto.argon2.Argon2PasswordEncoder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.DelegatingPasswordEncoder;
......@@ -48,6 +49,7 @@ import org.springframework.security.crypto.scrypt.SCryptPasswordEncoder;
public class SecurityConfig {
private final MyUserDetailsService userDetailService;
private final String SECRET_KEY = "123456";
public SecurityConfig(MyUserDetailsService userDetailsService) {
this.userDetailService = userDetailsService;
......@@ -61,10 +63,15 @@ public class SecurityConfig {
http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
.oidc(Customizer.withDefaults()); // Enable OpenID Connect 1.0
// http
// .authorizeRequests(authorizeRequests ->
// authorizeRequests
// .mvcMatchers("/assets/**", "/webjars/**", "/login").permitAll()
// .anyRequest().authenticated()
// )
http
// .csrf().disable()
// .authorizeHttpRequests()
// .anyRequest()
// Redirect to the login page when not authenticated from the authorization endpoint
.exceptionHandling((exceptions) -> exceptions
.authenticationEntryPoint(
......@@ -81,15 +88,39 @@ public class SecurityConfig {
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers("/", "/static/**", "/register**", "/home", "/about").permitAll()
.anyRequest().authenticated()
)
// Form login handles the redirect to the login page from the
// authorization server filter chain
.formLogin(Customizer.withDefaults());
.formLogin(
form -> form
.loginPage("/login")
.loginProcessingUrl("/login")
.defaultSuccessUrl("/users")
.permitAll()
)
.logout(
logout -> logout
.logoutUrl("/logout")
.logoutSuccessUrl("/")
.permitAll()
)
.rememberMe()
.rememberMeServices(getRememberMeServices())
.key(SECRET_KEY)
;
return http.build();
}
private TokenBasedRememberMeServices getRememberMeServices() {
TokenBasedRememberMeServices services = new TokenBasedRememberMeServices(SECRET_KEY, userDetailService);
services.setCookieName("remember-cookie");
services.setTokenValiditySeconds(100);
return services;
}
@Bean
OAuth2TokenCustomizer<JwtEncodingContext> jwtCustomizer() {
return context -> {
......
......@@ -15,26 +15,37 @@ import com.poc.alvachien.authserverdemo.model.UserAccount;
import com.poc.alvachien.authserverdemo.model.UserAccountDto;
import com.poc.alvachien.authserverdemo.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Controller
public class MainController {
private static final Logger log = LoggerFactory.getLogger(MainController.class);
private UserService userService;
public MainController(UserService userService) {
this.userService = userService;
}
@GetMapping("index")
@GetMapping("/")
public String home(){
return "index";
log.info("Requiring / and will redirect to /home");
return "home";
}
@GetMapping("/login")
public String loginForm() {
log.info("Requiring /login");
return "login";
}
// handler method to handle user registration request
@GetMapping("register")
public String showRegistrationForm(Model model){
log.info("Requiring /register");
UserAccountDto user = new UserAccountDto();
model.addAttribute("user", user);
return "register";
......@@ -45,6 +56,8 @@ public class MainController {
public String registration(@Valid @ModelAttribute("user") UserAccountDto user,
BindingResult result,
Model model){
log.info("Posting to /register/save");
UserAccount existing = userService.findByEmail(user.getEmail());
if (existing != null) {
result.rejectValue("email", null, "There is already an account registered with that email");
......@@ -59,6 +72,8 @@ public class MainController {
@GetMapping("/users")
public String listRegisteredUsers(Model model){
log.info("Requiring /users");
List<UserAccountDto> users = userService.findAllUsers();
model.addAttribute("users", users);
return "users";
......
......@@ -8,7 +8,6 @@ import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import com.poc.alvachien.authserverdemo.model.MyUserDetails;
import com.poc.alvachien.authserverdemo.model.UserAccount;
import com.poc.alvachien.authserverdemo.model.UserRole;
import com.poc.alvachien.authserverdemo.repository.UserAccountRepository;
......@@ -51,6 +50,7 @@ public class MyUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
log.info("Entering loadUserByUsername: " + email);
UserAccount user = userAccountRepository.findByEmail(email);
if (user != null) {
......
server.port:9600
spring.mvc.static-path-pattern: /static/**
#thymeleaf
spring.thymeleaf.cache=false
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:sqlserver://localhost;encrypt=true;database=authdemo;integratedSecurity=true;trustServerCertificate=true
#spring.datasource.username=springuser
......
.form-signin {
max-width: 330px;
padding: 15px;
}
.form-signin .form-floating:focus-within {
z-index: 2;
}
.form-signin input[type="email"] {
margin-bottom: -1px;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}
.form-signin input[type="password"] {
margin-bottom: 10px;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.container {
max-width: 960px;
}
.pricing-headerwebsite-header {
max-width: 700px;
}
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="408"><defs><linearGradient id="bs-logo-a" x1="76.079" x2="523.48" y1="10.798" y2="365.945" gradientUnits="userSpaceOnUse"><stop stop-color="#9013fe"/><stop offset="1" stop-color="#6610f2"/></linearGradient><linearGradient id="bs-logo-b" x1="193.508" x2="293.514" y1="109.74" y2="278.872" gradientUnits="userSpaceOnUse"><stop stop-color="#fff"/><stop offset="1" stop-color="#f1e5fc"/></linearGradient><filter xmlns="http://www.w3.org/2000/svg" id="bs-logo-c" width="197" height="249" x="161.901" y="83.457" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feColorMatrix in="SourceAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/><feOffset dy="4"/><feGaussianBlur stdDeviation="8"/><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.15 0"/><feBlend in2="BackgroundImageFix" result="effect1_dropShadow"/><feBlend in="SourceGraphic" in2="effect1_dropShadow" result="shape"/></filter></defs><path fill="url(#bs-logo-a)" d="M56.481 53.32C55.515 25.58 77.128 0 106.342 0h299.353c29.214 0 50.827 25.58 49.861 53.32-.928 26.647.277 61.165 8.964 89.31 8.715 28.232 23.411 46.077 47.48 48.37v26c-24.069 2.293-38.765 20.138-47.48 48.37-8.687 28.145-9.892 62.663-8.964 89.311.966 27.739-20.647 53.319-49.861 53.319H106.342c-29.214 0-50.827-25.58-49.86-53.319.927-26.648-.278-61.166-8.966-89.311C38.802 237.138 24.07 219.293 0 217v-26c24.069-2.293 38.802-20.138 47.516-48.37 8.688-28.145 9.893-62.663 8.965-89.31z"/><path fill="url(#bs-logo-b)" filter="url(#bs-logo-c)" stroke="#fff" d="M267.103 312.457c47.297 0 75.798-23.158 75.798-61.355 0-28.873-20.336-49.776-50.532-53.085v-1.203c22.185-3.609 39.594-24.211 39.594-47.219 0-32.783-25.882-54.138-65.322-54.138h-88.74v217h89.202zm-54.692-189.48h45.911c24.958 0 39.131 11.128 39.131 31.279 0 21.505-16.484 33.535-46.372 33.535h-38.67v-64.814zm0 161.961v-71.431h45.602c32.661 0 49.608 12.03 49.608 35.49 0 23.459-16.484 35.941-47.605 35.941h-47.605z"/></svg>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>AC Auth. System</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<style>
.bd-placeholder-img {
font-size: 1.125rem;
text-anchor: middle;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
@media (min-width: 768px) {
.bd-placeholder-img-lg {
font-size: 3.5rem;
}
}
.b-example-divider {
height: 3rem;
background-color: rgba(0, 0, 0, .1);
border: solid rgba(0, 0, 0, .15);
border-width: 1px 0;
box-shadow: inset 0 .5em 1.5em rgba(0, 0, 0, .1), inset 0 .125em .5em rgba(0, 0, 0, .15);
}
.b-example-vr {
flex-shrink: 0;
width: 1.5rem;
height: 100vh;
}
.bi {
vertical-align: -.125em;
fill: currentColor;
}
.nav-scroller {
position: relative;
z-index: 2;
height: 2.75rem;
overflow-y: hidden;
}
.nav-scroller .nav {
display: flex;
flex-wrap: nowrap;
padding-bottom: 1rem;
margin-top: -1px;
overflow-x: auto;
text-align: center;
white-space: nowrap;
-webkit-overflow-scrolling: touch;
}
</style>
<link rel="stylesheet" type="text/css" th:href="@{/static/css/website.css}"/>
</head>
<body>
<div class="container py-3">
<header>
<div class="d-flex flex-column flex-md-row align-items-center pb-3 mb-4 border-bottom">
<a href="/" class="d-flex align-items-center text-dark text-decoration-none">
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="32" class="me-2" viewBox="0 0 118 94"
role="img">
<title>AC Auth. Server</title>
<path fill-rule="evenodd" clip-rule="evenodd"
d="M24.509 0c-6.733 0-11.715 5.893-11.492 12.284.214 6.14-.064 14.092-2.066 20.577C8.943 39.365 5.547 43.485 0 44.014v5.972c5.547.529 8.943 4.649 10.951 11.153 2.002 6.485 2.28 14.437 2.066 20.577C12.794 88.106 17.776 94 24.51 94H93.5c6.733 0 11.714-5.893 11.491-12.284-.214-6.14.064-14.092 2.066-20.577 2.009-6.504 5.396-10.624 10.943-11.153v-5.972c-5.547-.529-8.934-4.649-10.943-11.153-2.002-6.484-2.28-14.437-2.066-20.577C105.214 5.894 100.233 0 93.5 0H24.508zM80 57.863C80 66.663 73.436 72 62.543 72H44a2 2 0 01-2-2V24a2 2 0 012-2h18.437c9.083 0 15.044 4.92 15.044 12.474 0 5.302-4.01 10.049-9.119 10.88v.277C75.317 46.394 80 51.21 80 57.863zM60.521 28.34H49.948v14.934h8.905c6.884 0 10.68-2.772 10.68-7.727 0-4.643-3.264-7.207-9.012-7.207zM49.948 49.2v16.458H60.91c7.167 0 10.964-2.876 10.964-8.281 0-5.406-3.903-8.178-11.425-8.178H49.948z"
fill="currentColor"></path>
</svg>
<span class="fs-4">AC Auth. Server</span>
</a>
<nav class="d-inline-flex mt-2 mt-md-0 ms-md-auto">
<a class="me-3 py-2 text-dark text-decoration-none" href="/login">Login</a>
<a class="me-3 py-2 text-dark text-decoration-none" href="/register">Register</a>
<a class="py-2 text-dark text-decoration-none" href="/about">About</a>
</nav>
</div>
<div class="website-header p-3 pb-md-4 mx-auto text-center">
<h1 class="display-4 fw-normal">AC Auth. Server</h1>
<p class="fs-5 text-muted">AC Auth. Server is an authorization server, including authentication server. It is used to for authorization server for apps.</p>
</div>
</header>
<main>
<div class="row row-cols-1 row-cols-md-3 mb-3 text-center">
<div class="col">
<div class="card mb-4 rounded-3 shadow-sm">
<div class="card-header py-3">
<h4 class="my-0 fw-normal">K.H.B.</h4>
</div>
<div class="card-body">
<h1 class="card-title pricing-card-title">Knowledge Habit Builder</h1>
<ul class="list-unstyled mt-3 mb-4">
<li>Knowledge Management</li>
<li>Exercise Bank</li>
<li>Learning history</li>
</ul>
<button type="button" class="w-100 btn btn-lg btn-outline-primary">Launch</button>
</div>
</div>
</div>
<div class="col">
<div class="card mb-4 rounded-3 shadow-sm">
<div class="card-header py-3">
<h4 class="my-0 fw-normal">Gallery</h4>
</div>
<div class="card-body">
<h1 class="card-title pricing-card-title">AC Photo Gallery</h1>
<ul class="list-unstyled mt-3 mb-4">
<li>Album Management</li>
<li>Photo Sharing</li>
<li>Access Code</li>
<li>Flexible Controls</li>
</ul>
<button type="button" class="w-100 btn btn-lg btn-primary">Launch</button>
</div>
</div>
</div>
<div class="col">
<div class="card mb-4 rounded-3 shadow-sm border-primary">
<div class="card-header py-3 text-bg-primary border-primary">
<h4 class="my-0 fw-normal">H.I.H.</h4>
</div>
<div class="card-body">
<h1 class="card-title pricing-card-title">Home Info. Hub</h1>
<ul class="list-unstyled mt-3 mb-4">
<li>Finance Records</li>
<li>Home Library</li>
<li>Finance Report</li>
<li>Common Events</li>
</ul>
<button type="button" class="w-100 btn btn-lg btn-primary">Launch</button>
</div>
</div>
</div>
</div>
</main>
<footer class="pt-4 my-md-5 pt-md-5 border-top">
<div class="row">
<div class="col-12 col-md">
<img class="mb-2" th:src="@{/static/img/log.svg}" alt="" width="24" height="19">
<small class="d-block mb-3 text-muted">© 2017–2023</small>
</div>
<div class="col-6 col-md">
<h5>Features</h5>
<ul class="list-unstyled text-small">
<li class="mb-1"><a class="link-secondary text-decoration-none" href="#">Cool stuff</a></li>
<li class="mb-1"><a class="link-secondary text-decoration-none" href="#">Random feature</a></li>
<li class="mb-1"><a class="link-secondary text-decoration-none" href="#">Team feature</a></li>
<li class="mb-1"><a class="link-secondary text-decoration-none" href="#">Stuff for
developers</a></li>
<li class="mb-1"><a class="link-secondary text-decoration-none" href="#">Another one</a></li>
<li class="mb-1"><a class="link-secondary text-decoration-none" href="#">Last time</a></li>
</ul>
</div>
<div class="col-6 col-md">
<h5>Resources</h5>
<ul class="list-unstyled text-small">
<li class="mb-1"><a class="link-secondary text-decoration-none" href="#">Resource</a></li>
<li class="mb-1"><a class="link-secondary text-decoration-none" href="#">Resource name</a></li>
<li class="mb-1"><a class="link-secondary text-decoration-none" href="#">Another resource</a>
</li>
<li class="mb-1"><a class="link-secondary text-decoration-none" href="#">Final resource</a></li>
</ul>
</div>
<div class="col-6 col-md">
<h5>About</h5>
<ul class="list-unstyled text-small">
<li class="mb-1"><a class="link-secondary text-decoration-none" href="#">Team</a></li>
<li class="mb-1"><a class="link-secondary text-decoration-none" href="#">Locations</a></li>
<li class="mb-1"><a class="link-secondary text-decoration-none" href="#">Privacy</a></li>
<li class="mb-1"><a class="link-secondary text-decoration-none" href="#">Terms</a></li>
</ul>
</div>
</div>
</footer>
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org"
>
<head>
<meta charset="UTF-8">
<title>Registration and Login System</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC"
crossorigin="anonymous">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="#">Registration and Login System</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link active" aria-current="page" th:href="@{/register}">Register</a>
</li>
<li class="nav-item">
<a class="nav-link active" aria-current="page" th:href="@{/login}">Login</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="container">
<div class="row">
<h1 class="text-center"> Welcome to Registration and Login System </h1>
</div>
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org"
>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Registration and Login System</title>
<title>AC Auth. System</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" th:href="@{/static/css/login.css}"/>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top" th:fragment="header">
<div class="container-fluid">
<a class="navbar-brand" th:href="@{/}">Registration and Login System</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
</div>
</nav>
<br />
<br />
<br />
<div class="container">
<div class="row">
<div class="col-md-6 offset-md-3">
<div th:if="${param.error}">
<div class="alert alert-danger">Invalid Email and Password.</div>
</div>
<div th:if="${param.logout}">
<div class="alert alert-success">You have been logged out.</div>
</div>
<div class="card">
<div class="card-header">
<h3 class="text-center">Login Form</h3>
</div>
<div class="card-body">
<form
method="post"
th:action="@{/login}"
class="form-horizontal"
role="form"
>
<div class="mb-3">
<label for="username" class="control-label">Email *</label>
<input type="text"
id="username"
name="username"
class="form-control"
placeholder="Email"
/>
</div>
<div class="container py-3">
<header>
<div class="d-flex flex-column flex-md-row align-items-center pb-3 mb-4 border-bottom">
<a href="/" class="d-flex align-items-center text-dark text-decoration-none">
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="32" class="me-2" viewBox="0 0 118 94"
role="img">
<title>AC Auth. Server</title>
<path fill-rule="evenodd" clip-rule="evenodd"
d="M24.509 0c-6.733 0-11.715 5.893-11.492 12.284.214 6.14-.064 14.092-2.066 20.577C8.943 39.365 5.547 43.485 0 44.014v5.972c5.547.529 8.943 4.649 10.951 11.153 2.002 6.485 2.28 14.437 2.066 20.577C12.794 88.106 17.776 94 24.51 94H93.5c6.733 0 11.714-5.893 11.491-12.284-.214-6.14.064-14.092 2.066-20.577 2.009-6.504 5.396-10.624 10.943-11.153v-5.972c-5.547-.529-8.934-4.649-10.943-11.153-2.002-6.484-2.28-14.437-2.066-20.577C105.214 5.894 100.233 0 93.5 0H24.508zM80 57.863C80 66.663 73.436 72 62.543 72H44a2 2 0 01-2-2V24a2 2 0 012-2h18.437c9.083 0 15.044 4.92 15.044 12.474 0 5.302-4.01 10.049-9.119 10.88v.277C75.317 46.394 80 51.21 80 57.863zM60.521 28.34H49.948v14.934h8.905c6.884 0 10.68-2.772 10.68-7.727 0-4.643-3.264-7.207-9.012-7.207zM49.948 49.2v16.458H60.91c7.167 0 10.964-2.876 10.964-8.281 0-5.406-3.903-8.178-11.425-8.178H49.948z"
fill="currentColor"></path>
</svg>
<span class="fs-4">AC Auth. Server</span>
</a>
<div class="mb-3">
<label for="password" class="control-label">Password *</label>
<input type="password"
id="password"
name="password"
class="form-control"
placeholder="Password"
/>
</div>
<nav class="d-inline-flex mt-2 mt-md-0 ms-md-auto">
<a class="me-3 py-2 text-dark text-decoration-none" href="/login">Login</a>
<a class="me-3 py-2 text-dark text-decoration-none" href="/register">Register</a>
<a class="py-2 text-dark text-decoration-none" href="/about">About</a>
</nav>
</div>
</header>
<div class="mb-3">
<button type="submit" class="btn btn-primary">Login</button>
<span> Not registered?
<a th:href="@{/register}"> Register/SignUp Here</a>
</span>
</div>
</form>
<main class="form-signin w-100 m-auto">
<form>
<img class="mb-4" th:src="@{img/log.svg}" alt="" width="72" height="57">
<h1 class="h3 mb-3 fw-normal">Please sign in</h1>
<div class="form-floating">
<input type="email" class="form-control" id="floatingInput" placeholder="name@example.com">
<label for="floatingInput">Email address</label>
</div>
<div class="form-floating">
<input type="password" class="form-control" id="floatingPassword" placeholder="Password">
<label for="floatingPassword">Password</label>
</div>
<div class="checkbox mb-3">
<label>
<input type="checkbox" value="remember-me"> Remember me </label>
</div>
<button class="w-100 btn btn-lg btn-primary" type="submit">Sign in</button>
</form>
</main>
<footer class="pt-4 my-md-5 pt-md-5 border-top">
<div class="row">
<div class="col-12 col-md">
<img class="mb-2" th:src="@{/static/img/log.svg}" alt="" width="24" height="19">
<small class="d-block mb-3 text-muted">© 2017–2023</small>
</div>
<div class="col-6 col-md">
<h5>Features</h5>
<ul class="list-unstyled text-small">
<li class="mb-1"><a class="link-secondary text-decoration-none" href="#">Cool stuff</a></li>
<li class="mb-1"><a class="link-secondary text-decoration-none" href="#">Random feature</a></li>
<li class="mb-1"><a class="link-secondary text-decoration-none" href="#">Team feature</a></li>
<li class="mb-1"><a class="link-secondary text-decoration-none" href="#">Stuff for
developers</a></li>
<li class="mb-1"><a class="link-secondary text-decoration-none" href="#">Another one</a></li>
<li class="mb-1"><a class="link-secondary text-decoration-none" href="#">Last time</a></li>
</ul>
</div>
<div class="col-6 col-md">
<h5>Resources</h5>
<ul class="list-unstyled text-small">
<li class="mb-1"><a class="link-secondary text-decoration-none" href="#">Resource</a></li>
<li class="mb-1"><a class="link-secondary text-decoration-none" href="#">Resource name</a></li>
<li class="mb-1"><a class="link-secondary text-decoration-none" href="#">Another resource</a>
</li>
<li class="mb-1"><a class="link-secondary text-decoration-none" href="#">Final resource</a></li>
</ul>
</div>
<div class="col-6 col-md">
<h5>About</h5>
<ul class="list-unstyled text-small">
<li class="mb-1"><a class="link-secondary text-decoration-none" href="#">Team</a></li>
<li class="mb-1"><a class="link-secondary text-decoration-none" href="#">Locations</a></li>
<li class="mb-1"><a class="link-secondary text-decoration-none" href="#">Privacy</a></li>
<li class="mb-1"><a class="link-secondary text-decoration-none" href="#">Terms</a></li>
</ul>
</div>
</div>
</div>
</div>
</div>
</footer>
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>AC Auth. System</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" th:href="@{css/login.css}"/>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top" th:fragment="header">
<div class="container-fluid">
<a class="navbar-brand" th:href="@{/}">AC Identity System</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse"
data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false"
aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
</div>
</nav>
<br />
<br />
<br />
<div class="container">
<div class="row">
<div class="col-md-6 offset-md-3">
<div th:if="${param.error}">
<div class="alert alert-danger">Invalid Email and Password.</div>
</div>
<div th:if="${param.logout}">
<div class="alert alert-success">You have been logged out.</div>
</div>
<div class="card">
<div class="card-header">
<h3 class="text-center">Login Form</h3>
</div>
<div class="card-body">
<form method="post" th:action="@{/login}" class="form-horizontal" role="form">
<div class="mb-3">
<label for="username" class="control-label">Email *</label>
<input type="text" id="username" name="username" class="form-control"
placeholder="Email" />
</div>
<div class="mb-3">
<label for="password" class="control-label">Password *</label>
<input type="password" id="password" name="password" class="form-control"
placeholder="Password" />
</div>
<div class="mb-3">
<button type="submit" class="btn btn-primary">Login</button>
<span> Not registered?
<a th:href="@{/register}"> Register/SignUp Here</a>
</span>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>AC Auth. System</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top" th:fragment="header">
<div class="container-fluid">
<a class="navbar-brand" th:href="@{/}">Registration and Login System</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse"
data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false"
aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
</div>
</nav>
<br />
<br />
<br />
<div class="container">
<div class="row col-md-8 offset-md-2">
<div class="card">
<div th:if="${param.success}">
<div class="alert alert-info">You've successfully registered
to our app!</div>
</div>
<div class="card-header">
<h2 class="text-center">Registration</h2>
</div>
<div class="card-body">
<form method="post" role="form" th:action="@{/register/save}" th:object="${user}">
<div class="form-group mb-3">
<label class="form-label">First Name</label>
<input class="form-control" id="firstName" name="firstName" placeholder="Enter first name"
th:field="*{firstName}" type="text" />
<p th:errors="*{firstName}" class="text-danger" th:if="${#fields.hasErrors('firstName')}">
</p>
</div>
<div class="form-group mb-3">
<label class="form-label">Last Name</label>
<input class="form-control" id="lastName" name="lastName" placeholder="Enter last name"
th:field="*{lastName}" type="text" />
<p th:errors="*{lastName}" class="text-danger" th:if="${#fields.hasErrors('lastName')}">
</p>
</div>
<div class="form-group mb-3">
<label class="form-label">Email</label>
<input class="form-control" id="email" name="email" placeholder="Enter email address"
th:field="*{email}" type="email" />
<p th:errors="*{email}" class="text-danger" th:if="${#fields.hasErrors('email')}">
</p>
</div>
<div class="form-group mb-3">
<label class="form-label">Password</label>
<input class="form-control" id="password" name="password" placeholder="Enter password"
th:field="*{password}" type="password" />
<p th:errors="*{password}" class="text-danger" th:if="${#fields.hasErrors('password')}">
</p>
</div>
<div class="form-group mb-3">
<button class="btn btn-primary" type="submit">Register</button>
<span>Already registered? <a href="/" th:href="@{/login}">Login
here</a></span>
</div>
</form>
</div>
</div>
</div>
</div>
</body>
</html>
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org"
>
<head>
<meta charset="UTF-8">
<title>Registration and Login System</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top" th:fragment="header">
<div class="container-fluid">
<a class="navbar-brand" th:href="@{/}">Registration and Login System</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
</div>
</nav>
<br />
<br />
<br />
<div class="container">
<div class="row col-md-8 offset-md-2">
<div class="card">
<div th:if="${param.success}">
<div class="alert alert-info">You've successfully registered
to our app!</div>
</div>
<div class="card-header">
<h2 class="text-center">Registration</h2>
</div>
<div class="card-body">
<form method="post" role="form" th:action="@{/register/save}" th:object="${user}">
<div class="form-group mb-3">
<label class="form-label">First Name</label>
<input class="form-control"
id="firstName"
name="firstName"
placeholder="Enter first name"
th:field="*{firstName}"
type="text"
/>
<p th:errors="*{firstName}" class="text-danger"
th:if="${#fields.hasErrors('firstName')}">
</p>
</div>
<div class="form-group mb-3">
<label class="form-label">Last Name</label>
<input class="form-control"
id="lastName"
name="lastName"
placeholder="Enter last name"
th:field="*{lastName}"
type="text"
/>
<p th:errors="*{lastName}" class="text-danger"
th:if="${#fields.hasErrors('lastName')}">
</p>
</div>
<div class="form-group mb-3">
<label class="form-label">Email</label>
<input class="form-control"
id="email"
name="email"
placeholder="Enter email address"
th:field="*{email}"
type="email"
/>
<p th:errors="*{email}" class="text-danger"
th:if="${#fields.hasErrors('email')}">
</p>
</div>
<div class="form-group mb-3">
<label class="form-label">Password</label>
<input class="form-control"
id="password"
name="password"
placeholder="Enter password"
th:field="*{password}"
type="password"
/>
<p th:errors="*{password}" class="text-danger"
th:if="${#fields.hasErrors('password')}">
</p>
</div>
<div class="form-group mb-3">
<button class="btn btn-primary" type="submit">Register</button>
<span>Already registered? <a href="/" th:href="@{/login}">Login
here</a></span>
</div>
</form>
</div>
</div>
</div>
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org"
>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Registration and Login System</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC"
crossorigin="anonymous">
<title>AC Auth. System</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="#">Registration and Login System</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link active" aria-current="page" th:href="@{/register}">Register</a>
</li>
<li class="nav-item">
<a class="nav-link active" aria-current="page" th:href="@{/logout}">Logout</a>
</li>
</ul>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="#">Registration and Login System</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse"
data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false"
aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link active" aria-current="page" th:href="@{/register}">Register</a>
</li>
<li class="nav-item">
<a class="nav-link active" aria-current="page" th:href="@{/logout}">Logout</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="container">
<div class="row">
<h1> Registered Users </h1>
</div>
<table class="table table-striped table-bordered table-hover">
<thead class="table-dark">
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
</tr>
</thead>
<tbody>
<tr th:each="user: ${users}">
<td th:text="${user.firstName}"></td>
<td th:text="${user.lastName}"></td>
<td th:text="${user.email}"></td>
</tr>
</tbody>
</table>
</div>
</nav>
<div class="container">
<div class="row">
<h1> Registered Users </h1>
</div>
<table class="table table-striped table-bordered table-hover">
<thead class="table-dark">
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
</tr>
</thead>
<tbody>
<tr th:each="user: ${users}">
<td th:text="${user.firstName}"></td>
<td th:text="${user.lastName}"></td>
<td th:text="${user.email}"></td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
\ No newline at end of file
</html>
......@@ -22,6 +22,8 @@ This article adds the JPA implementations to client/authorization/authorization-
- [Spring Security Architecture](https://docs.spring.io/spring-security/reference/servlet/architecture.html)
- [Registration Login example using Spring Boot/Spring Security/JPA/MySql/Thymeleaf](https://www.javaguides.net/2019/08/registration-login-example-using-springboot-spring-data-jpa-hibernate-mysql-thymeleaf.html)
- [Source repository](https://github.com/RameshMF/registration-login-springboot-security-thymeleaf)
- [Spring Boot + Spring Security + Thymeleaf](https://www.jianshu.com/p/dcf227d53ab5)
- [Source repository](https://github.com/Smith-Cruise/Spring-Boot-Security-Thymeleaf-Demo)
To be read?
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册