Added Login
This commit is contained in:
parent
af5248faed
commit
90ccb8a00c
33
build.gradle
33
build.gradle
@ -1,9 +1,20 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'org.flywaydb:flyway-database-postgresql:11.3.2'
|
||||
classpath 'org.postgresql:postgresql:42.7.5'
|
||||
}
|
||||
}
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'org.springframework.boot' version '3.4.2'
|
||||
id 'org.flywaydb.flyway' version "11.3.2"
|
||||
id 'io.spring.dependency-management' version '1.1.7'
|
||||
}
|
||||
|
||||
|
||||
group = 'com.bernard'
|
||||
version = '0.0.1-SNAPSHOT'
|
||||
|
||||
@ -21,15 +32,33 @@ dependencies {
|
||||
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-security'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-web'
|
||||
implementation 'org.flywaydb:flyway-core'
|
||||
implementation 'org.flywaydb:flyway-database-postgresql'
|
||||
implementation 'org.springframework:spring-jdbc'
|
||||
implementation 'org.flywaydb:flyway-core:11.3.2'
|
||||
implementation 'org.flywaydb:flyway-database-postgresql:11.3.2'
|
||||
implementation 'org.springframework.session:spring-session-jdbc'
|
||||
implementation 'jakarta.validation:jakarta.validation-api:3.1.1'
|
||||
developmentOnly 'org.springframework.boot:spring-boot-devtools'
|
||||
developmentOnly 'org.springframework.boot:spring-boot-docker-compose'
|
||||
runtimeOnly 'org.postgresql:postgresql'
|
||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||
|
||||
//Lombok
|
||||
compileOnly 'org.projectlombok:lombok:1.18.36'
|
||||
annotationProcessor 'org.projectlombok:lombok:1.18.36'
|
||||
|
||||
testCompileOnly 'org.projectlombok:lombok:1.18.36'
|
||||
testAnnotationProcessor 'org.projectlombok:lombok:1.18.36'
|
||||
}
|
||||
|
||||
flyway {
|
||||
url = "jdbc:postgresql://127.0.0.1:10051/misael"
|
||||
user = 'misael'
|
||||
password = 'misael-dev'
|
||||
driver = 'org.postgresql.Driver'
|
||||
schemas = ['misael']
|
||||
}
|
||||
|
||||
tasks.named('test') {
|
||||
|
||||
@ -2,8 +2,8 @@ services:
|
||||
postgres:
|
||||
image: 'postgres:latest'
|
||||
environment:
|
||||
- 'POSTGRES_DB=mydatabase'
|
||||
- 'POSTGRES_PASSWORD=secret'
|
||||
- 'POSTGRES_USER=myuser'
|
||||
- 'POSTGRES_DB=misael'
|
||||
- 'POSTGRES_PASSWORD=misael-dev'
|
||||
- 'POSTGRES_USER=misael'
|
||||
ports:
|
||||
- '5432'
|
||||
- '10051:5432'
|
||||
|
||||
@ -0,0 +1,45 @@
|
||||
package com.bernard.misael;
|
||||
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.bernard.misael.model.Role;
|
||||
import com.bernard.misael.model.User;
|
||||
import com.bernard.misael.repository.UserRepository;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class CustomUserDetailsService implements UserDetailsService {
|
||||
|
||||
private UserRepository userRepository;
|
||||
|
||||
public CustomUserDetailsService(UserRepository userRepository) {
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String pseudo) throws UsernameNotFoundException {
|
||||
User user = userRepository.findByName(pseudo);
|
||||
|
||||
if (user != null) {
|
||||
return new org.springframework.security.core.userdetails.User(user.getName(),
|
||||
user.getPassword(),
|
||||
mapRolesToAuthorities(user.getRoles()));
|
||||
}else{
|
||||
throw new UsernameNotFoundException("Invalid username or password.");
|
||||
}
|
||||
}
|
||||
|
||||
private Collection < ? extends GrantedAuthority> mapRolesToAuthorities(Collection<Role> roles) {
|
||||
Collection < ? extends GrantedAuthority> mapRoles = roles.stream()
|
||||
.map(role -> new SimpleGrantedAuthority(role.getName()))
|
||||
.collect(Collectors.toList());
|
||||
return mapRoles;
|
||||
}
|
||||
}
|
||||
54
src/main/java/com/bernard/misael/SpringSecurity.java
Normal file
54
src/main/java/com/bernard/misael/SpringSecurity.java
Normal file
@ -0,0 +1,54 @@
|
||||
package com.bernard.misael;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
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.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
public class SpringSecurity {
|
||||
|
||||
@Autowired
|
||||
private UserDetailsService userDetailsService;
|
||||
|
||||
@Bean
|
||||
public static PasswordEncoder passwordEncoder(){
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
http.csrf().disable()
|
||||
.authorizeHttpRequests((authorize) ->
|
||||
authorize.requestMatchers("/**").permitAll()
|
||||
// .requestMatchers("/index").permitAll()
|
||||
// .requestMatchers("/users").hasRole("ADMIN")
|
||||
).formLogin(
|
||||
form -> form
|
||||
.loginPage("/login")
|
||||
.loginProcessingUrl("/login")
|
||||
.defaultSuccessUrl("/")
|
||||
.permitAll()
|
||||
).logout(
|
||||
logout -> logout
|
||||
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
|
||||
.permitAll()
|
||||
);
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.userDetailsService(userDetailsService)
|
||||
.passwordEncoder(passwordEncoder());
|
||||
}
|
||||
}
|
||||
28
src/main/java/com/bernard/misael/model/Role.java
Normal file
28
src/main/java/com/bernard/misael/model/Role.java
Normal file
@ -0,0 +1,28 @@
|
||||
package com.bernard.misael.model;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Entity
|
||||
@Table(name="roles")
|
||||
public class Role
|
||||
{
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable=false, unique=true)
|
||||
private String name;
|
||||
|
||||
@ManyToMany(mappedBy="roles")
|
||||
private List<User> users;
|
||||
}
|
||||
37
src/main/java/com/bernard/misael/model/User.java
Normal file
37
src/main/java/com/bernard/misael/model/User.java
Normal file
@ -0,0 +1,37 @@
|
||||
package com.bernard.misael.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Entity
|
||||
@Table(name="users")
|
||||
public class User
|
||||
{
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable=false)
|
||||
private String name;
|
||||
|
||||
@Column(nullable=false)
|
||||
private String password;
|
||||
|
||||
@ManyToMany(fetch = FetchType.EAGER, cascade=CascadeType.ALL)
|
||||
@JoinTable(
|
||||
name="users_roles",
|
||||
joinColumns={@JoinColumn(name="USER_ID", referencedColumnName="ID")},
|
||||
inverseJoinColumns={@JoinColumn(name="ROLE_ID", referencedColumnName="ID")})
|
||||
private List<Role> roles = new ArrayList<>();
|
||||
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
package com.bernard.misael.repository;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import com.bernard.misael.model.Role;
|
||||
|
||||
public interface RoleRepository extends JpaRepository<Role, Long> {
|
||||
|
||||
Role findByName(String name);
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
package com.bernard.misael.repository;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import com.bernard.misael.model.User;
|
||||
|
||||
public interface UserRepository extends JpaRepository<User, Long> {
|
||||
|
||||
User findByName(String pseudo);
|
||||
|
||||
}
|
||||
14
src/main/java/com/bernard/misael/service/UserService.java
Normal file
14
src/main/java/com/bernard/misael/service/UserService.java
Normal file
@ -0,0 +1,14 @@
|
||||
package com.bernard.misael.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.bernard.misael.model.User;
|
||||
import com.bernard.misael.service.dto.UserDto;
|
||||
|
||||
public interface UserService {
|
||||
void saveUser(UserDto userDto);
|
||||
|
||||
User findUserByName(String name);
|
||||
|
||||
List<UserDto> findAllUsers();
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
package com.bernard.misael.service;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.bernard.misael.model.Role;
|
||||
import com.bernard.misael.model.User;
|
||||
import com.bernard.misael.repository.RoleRepository;
|
||||
import com.bernard.misael.repository.UserRepository;
|
||||
import com.bernard.misael.service.dto.UserDto;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class UserServiceImpl implements UserService {
|
||||
|
||||
private UserRepository userRepository;
|
||||
private RoleRepository roleRepository;
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
public UserServiceImpl(UserRepository userRepository,
|
||||
RoleRepository roleRepository,
|
||||
PasswordEncoder passwordEncoder) {
|
||||
this.userRepository = userRepository;
|
||||
this.roleRepository = roleRepository;
|
||||
this.passwordEncoder = passwordEncoder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveUser(UserDto userDto) {
|
||||
User user = new User();
|
||||
user.setName(userDto.getName());
|
||||
// encrypt the password using spring security
|
||||
user.setPassword(passwordEncoder.encode(userDto.getPassword()));
|
||||
|
||||
Role role = roleRepository.findByName("ROLE_ADMIN");
|
||||
if(role == null){
|
||||
role = checkRoleExist();
|
||||
}
|
||||
user.setRoles(Arrays.asList(role));
|
||||
userRepository.save(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public User findUserByName(String name) {
|
||||
return userRepository.findByName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserDto> findAllUsers() {
|
||||
List<User> users = userRepository.findAll();
|
||||
return users.stream()
|
||||
.map((user) -> mapToUserDto(user))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private UserDto mapToUserDto(User user){
|
||||
UserDto userDto = new UserDto();
|
||||
userDto.setName(user.getName());
|
||||
return userDto;
|
||||
}
|
||||
|
||||
private Role checkRoleExist(){
|
||||
Role role = new Role();
|
||||
role.setName("ROLE_ADMIN");
|
||||
return roleRepository.save(role);
|
||||
}
|
||||
}
|
||||
21
src/main/java/com/bernard/misael/service/dto/UserDto.java
Normal file
21
src/main/java/com/bernard/misael/service/dto/UserDto.java
Normal file
@ -0,0 +1,21 @@
|
||||
package com.bernard.misael.service.dto;
|
||||
|
||||
import jakarta.validation.constraints.Email;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class UserDto
|
||||
{
|
||||
private Long id;
|
||||
@NotEmpty(message = "User name should not be empty")
|
||||
private String name;
|
||||
@NotEmpty(message = "Password should not be empty")
|
||||
private String password;
|
||||
}
|
||||
81
src/main/java/com/bernard/misael/web/AuthController.java
Normal file
81
src/main/java/com/bernard/misael/web/AuthController.java
Normal file
@ -0,0 +1,81 @@
|
||||
package com.bernard.misael.web;
|
||||
|
||||
import org.springframework.security.authentication.AnonymousAuthenticationToken;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
|
||||
import com.bernard.misael.model.User;
|
||||
import com.bernard.misael.service.UserService;
|
||||
import com.bernard.misael.service.dto.UserDto;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
|
||||
@Controller
|
||||
public class AuthController {
|
||||
|
||||
private UserService userService;
|
||||
|
||||
public AuthController(UserService userService) {
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
@GetMapping("/login")
|
||||
public String loginPage() {
|
||||
return "login";
|
||||
}
|
||||
|
||||
public User getLoggedInUser() {
|
||||
if(SecurityContextHolder.getContext().getAuthentication().getPrincipal()
|
||||
instanceof org.springframework.security.core.userdetails.User){
|
||||
org.springframework.security.core.userdetails.User user
|
||||
= (org.springframework.security.core.userdetails.User)
|
||||
SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
return userService.findUserByName(user.getUsername());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/")
|
||||
public String index(Model model) {
|
||||
if(SecurityContextHolder.getContext().getAuthentication().getPrincipal() instanceof org.springframework.security.core.userdetails.User){
|
||||
org.springframework.security.core.userdetails.User user
|
||||
= (org.springframework.security.core.userdetails.User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
model.addAttribute("username", user.getUsername());
|
||||
}else{
|
||||
model.addAttribute("username", "no-one");
|
||||
}
|
||||
return "index";
|
||||
}
|
||||
|
||||
@GetMapping("/adduser")
|
||||
public String showRegistrationForm(Model model){
|
||||
// create model object to store form data
|
||||
UserDto user = new UserDto();
|
||||
model.addAttribute("user", user);
|
||||
return "adduser";
|
||||
}
|
||||
|
||||
@PostMapping("/adduser/save")
|
||||
public String registration(@Valid @ModelAttribute("user") UserDto userDto,
|
||||
BindingResult result,
|
||||
Model model){
|
||||
User existingUser = userService.findUserByName("mysaa");
|
||||
|
||||
if(existingUser != null){
|
||||
result.reject("User is already registered");
|
||||
}
|
||||
|
||||
if(result.hasErrors()){
|
||||
model.addAttribute("user", userDto);
|
||||
return "/adduser";
|
||||
}
|
||||
userService.saveUser(userDto);
|
||||
return "redirect:/adduser?success";
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,12 @@
|
||||
package com.bernard.misael.web;
|
||||
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import com.bernard.misael.service.dto.UserDto;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
|
||||
@ -23,11 +28,6 @@ public class QuestionsController {
|
||||
public String getForms() {
|
||||
return "forms.html";
|
||||
}
|
||||
@GetMapping("/login")
|
||||
public String loginPage() {
|
||||
return "login.html";
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -1,2 +0,0 @@
|
||||
spring.application.name=Misael
|
||||
spring.session.jdbc.initialize-schema=always
|
||||
27
src/main/resources/application.yml
Normal file
27
src/main/resources/application.yml
Normal file
@ -0,0 +1,27 @@
|
||||
spring:
|
||||
datasource:
|
||||
url: jdbc:mysql://127.0.0.1:10051/misael
|
||||
username: misael
|
||||
password: misael-dev
|
||||
hikari:
|
||||
schema: misael
|
||||
flyway:
|
||||
enabled: true
|
||||
locations: classpath:db/migration/structure, classpath:db/migration/data
|
||||
validate-on-migrate: true
|
||||
default-schema: misael
|
||||
|
||||
# jpa:
|
||||
# properties:
|
||||
# javax:
|
||||
# persistence:
|
||||
# schema-generation:
|
||||
# create-source: metadata
|
||||
# scripts:
|
||||
# action: update
|
||||
# create-target: db-migration.sql
|
||||
# database:
|
||||
# action: none
|
||||
# hibernate:
|
||||
# ddl-auto: none
|
||||
# generate-ddl: true
|
||||
@ -0,0 +1,7 @@
|
||||
create table roles (id bigint generated by default as identity, name varchar(255) not null, primary key (id));
|
||||
create table users (id bigint generated by default as identity, name varchar(255) not null, password varchar(255) not null, primary key (id));
|
||||
create table users_roles (user_id bigint not null, role_id bigint not null);
|
||||
alter table if exists roles drop constraint if exists UKofx66keruapi6vyqpv6f2or37;
|
||||
alter table if exists roles add constraint UKofx66keruapi6vyqpv6f2or37 unique (name);
|
||||
alter table if exists users_roles add constraint FKj6m8fwv7oqv74fcehir1a9ffy foreign key (role_id) references roles;
|
||||
alter table if exists users_roles add constraint FK2o0jvgh89lemvvo17cbqvdxaa foreign key (user_id) references users;
|
||||
45
src/main/resources/templates/adduser.html
Normal file
45
src/main/resources/templates/adduser.html
Normal file
@ -0,0 +1,45 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr" dir="ltr">
|
||||
<head>
|
||||
<div th:replace="~{html-head}"/>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div th:replace="~{header}"/>
|
||||
<main>
|
||||
|
||||
<div th:if="${param.success}">
|
||||
You have successfully registered our app!
|
||||
</div>
|
||||
<form
|
||||
method="post"
|
||||
role="form"
|
||||
th:action="@{/adduser/save}"
|
||||
th:object="${user}"
|
||||
>
|
||||
<label for="name">Name</label>
|
||||
<input
|
||||
id="name"
|
||||
name="name"
|
||||
placeholder="Enter pseudo"
|
||||
th:field="*{name}"
|
||||
type="text"
|
||||
/>
|
||||
<p th:errors = "*{name}" th:if="${#fields.hasErrors('name')}"></p>
|
||||
|
||||
<label for="password">Password</label>
|
||||
<input
|
||||
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>
|
||||
|
||||
<button class="btn btn-primary" type="submit">Register</button>
|
||||
</form>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@ -4,7 +4,7 @@
|
||||
<ul class="menu">
|
||||
<li><a href="/questions/quizz">Quizz</a></li>
|
||||
<li><a href="/questions/forms">Forms</a></li>
|
||||
<li><a href="/questions/login">Login</a></li>
|
||||
<li><a href="/login">Login</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
13
src/main/resources/templates/index.html
Normal file
13
src/main/resources/templates/index.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr" dir="ltr">
|
||||
<head>
|
||||
<div th:replace="~{html-head}"/>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div th:replace="~{header}"/>
|
||||
<main>
|
||||
Logged in as <div th:text="${username}"></div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@ -8,14 +8,24 @@
|
||||
<div th:replace="~{header}"/>
|
||||
<main>
|
||||
|
||||
<form>
|
||||
<label for="login-pseudo">Pseudo :</label>
|
||||
<input type="text" id="login-pseudo" name="pseudo"/>
|
||||
<div th:if="${param.error}">
|
||||
<div class="alert alert-danger">Invalid Email or Password</div><br/>
|
||||
</div>
|
||||
<div th:if="${param.logout}">
|
||||
<div class="alert alert-success"> You have been logged out.</div><br/>
|
||||
</div>
|
||||
|
||||
<form
|
||||
method="post"
|
||||
role="form"
|
||||
th:action="@{/login}">
|
||||
<label for="username">Pseudo :</label>
|
||||
<input type="text" id="username" name="username"/>
|
||||
<br/>
|
||||
<label for="login-password">Mot de passe :</label>
|
||||
<input type="text" id="login-password" name="password"/>
|
||||
<label for="password">Mot de passe :</label>
|
||||
<input type="password" id="password" name="password"/>
|
||||
<br/>
|
||||
<input id="connect" type="button">Se connecter</input>
|
||||
<input id="connect" type="submit">Se connecter</input>
|
||||
</form>
|
||||
</main>
|
||||
</body>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user