Init api and security.
This commit is contained in:
33
.gitignore
vendored
Normal file
33
.gitignore
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
HELP.md
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
87
pom.xml
Normal file
87
pom.xml
Normal file
@@ -0,0 +1,87 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.3.1.RELEASE</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>org.takiguchi</groupId>
|
||||
<artifactId>starter</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>starter</name>
|
||||
<description>Demo project for Spring Boot</description>
|
||||
|
||||
<properties>
|
||||
<java.version>11</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<scope>runtime</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt</artifactId>
|
||||
<version>0.9.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.junit.vintage</groupId>
|
||||
<artifactId>junit-vintage-engine</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
11
src/main/java/org/takiguchi/starter/StarterApplication.java
Normal file
11
src/main/java/org/takiguchi/starter/StarterApplication.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package org.takiguchi.starter;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class StarterApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(StarterApplication.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package org.takiguchi.starter.config.security;
|
||||
|
||||
import io.jsonwebtoken.Claims;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.springframework.http.HttpHeaders.AUTHORIZATION;
|
||||
import static org.takiguchi.tamotsu.client.constant.Constant.AUTHORITIES_KEY;
|
||||
|
||||
public class JwtRequestFilter extends OncePerRequestFilter {
|
||||
private static final String TOKEN_PREFIX = "Bearer ";
|
||||
|
||||
private final TokenProvider tokenProvider;
|
||||
|
||||
public JwtRequestFilter(TokenProvider tokenProvider) {
|
||||
this.tokenProvider = tokenProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
|
||||
String token = getTokenFromHeaders(request);
|
||||
|
||||
// Once we get the token validate it.
|
||||
if (SecurityContextHolder.getContext().getAuthentication() == null) {
|
||||
String username = null;
|
||||
try {
|
||||
username = tokenProvider.getUsernameFromToken(token);
|
||||
} catch (Exception e) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
if (username != null && !tokenProvider.isTokenExpired(token)) {
|
||||
Claims claims = tokenProvider.getAllClaimsFromToken(token);
|
||||
List<String> roles = claims.get(AUTHORITIES_KEY, List.class);
|
||||
|
||||
List<SimpleGrantedAuthority> authorities = roles.stream()
|
||||
.map(SimpleGrantedAuthority::new)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(username, username, authorities);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
}
|
||||
}
|
||||
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
private String getTokenFromHeaders(HttpServletRequest request) {
|
||||
String token = null;
|
||||
|
||||
String authHeader = request.getHeader(AUTHORIZATION);
|
||||
if (authHeader != null && authHeader.startsWith(TOKEN_PREFIX)) {
|
||||
token = authHeader.replace(TOKEN_PREFIX, "");
|
||||
} else {
|
||||
logger.debug("Couldn't find bearer string, will ignore the header.");
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package org.takiguchi.starter.config.security;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
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.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import static org.springframework.http.HttpMethod.GET;
|
||||
import static org.springframework.http.HttpMethod.OPTIONS;
|
||||
import static org.springframework.security.config.http.SessionCreationPolicy.STATELESS;
|
||||
|
||||
@EnableWebSecurity
|
||||
@Configuration
|
||||
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.cors().disable()
|
||||
.exceptionHandling()
|
||||
.authenticationEntryPoint((request, response, authResponse) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED))
|
||||
.accessDeniedHandler((request, response, accessDeniedException) -> response.sendError(HttpServletResponse.SC_FORBIDDEN))
|
||||
.and()
|
||||
.addFilterBefore(jwtRequestFilter(), UsernamePasswordAuthenticationFilter.class)
|
||||
.sessionManagement().sessionCreationPolicy(STATELESS)
|
||||
.and()
|
||||
.requiresChannel()
|
||||
.anyRequest()
|
||||
.requiresSecure()
|
||||
.and()
|
||||
.csrf().disable()
|
||||
.authorizeRequests()
|
||||
.antMatchers(
|
||||
"/api/auth/login",
|
||||
"/api/health/check"
|
||||
).permitAll()
|
||||
.antMatchers(OPTIONS).permitAll()
|
||||
.anyRequest().authenticated();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public BCryptPasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
@Bean
|
||||
public TokenProvider tokenProvider(@Value("${app.security.signing-key}") String signingKey,
|
||||
@Value("${app.security.access-token-validity-seconds}") int accessTokenValiditySeconds) {
|
||||
return new TokenProvider(signingKey, accessTokenValiditySeconds);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JwtRequestFilter jwtRequestFilter() {
|
||||
return new JwtRequestFilter(tokenProvider());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package org.takiguchi.starter.config.security;
|
||||
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.takiguchi.starter.model.dao.User;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class TokenProvider {
|
||||
|
||||
private static final String AUTHORITIES_KEY = "scopes";
|
||||
private final String signingKey;
|
||||
private final int accessTokenValiditySeconds;
|
||||
|
||||
public TokenProvider(String signingKey, int accessTokenValiditySeconds) {
|
||||
this.signingKey = signingKey;
|
||||
this.accessTokenValiditySeconds = accessTokenValiditySeconds;
|
||||
}
|
||||
|
||||
|
||||
public String getUserEmailFromToken(String token) {
|
||||
return getClaimFromToken(token, Claims::getSubject);
|
||||
}
|
||||
|
||||
public Date getExpirationDateFromToken(String token) {
|
||||
return getClaimFromToken(token, Claims::getExpiration);
|
||||
}
|
||||
|
||||
public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
|
||||
Claims claims = getAllClaimsFromToken(token);
|
||||
return claimsResolver.apply(claims);
|
||||
}
|
||||
|
||||
public Boolean isTokenExpired(String token) {
|
||||
final Date expiration = getExpirationDateFromToken(token);
|
||||
return expiration.before(new Date());
|
||||
}
|
||||
|
||||
public Claims getAllClaimsFromToken(String token) {
|
||||
return Jwts.parser()
|
||||
.setSigningKey(signingKey)
|
||||
.parseClaimsJws(token)
|
||||
.getBody();
|
||||
}
|
||||
|
||||
public String generateToken(User user) {
|
||||
return Jwts.builder()
|
||||
.setSubject(user.getEmail())
|
||||
.claim(AUTHORITIES_KEY, getAuthorities(user))
|
||||
.signWith(SignatureAlgorithm.HS256, signingKey)
|
||||
.setIssuedAt(new Date(System.currentTimeMillis()))
|
||||
.setExpiration(new Date(System.currentTimeMillis() + accessTokenValiditySeconds * 1000))
|
||||
.compact();
|
||||
}
|
||||
|
||||
private List<String> getAuthorities(User user) {
|
||||
List<String> authorities = Collections.emptyList();
|
||||
// if (!CollectionUtils.isEmpty(user.getRoles())) {
|
||||
// authorities = user.getRoles().stream()
|
||||
// .map(Role::getName)
|
||||
// .collect(Collectors.toList());
|
||||
// }
|
||||
return authorities;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package org.takiguchi.starter.controller;
|
||||
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.takiguchi.starter.config.security.TokenProvider;
|
||||
import org.takiguchi.starter.exception.BadRequestException;
|
||||
import org.takiguchi.starter.model.dao.User;
|
||||
import org.takiguchi.starter.model.dto.LoginRequest;
|
||||
import org.takiguchi.starter.model.dto.LoginResponse;
|
||||
import org.takiguchi.starter.repository.UserRepository;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/auth")
|
||||
public class AuthenticationController {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
private final TokenProvider tokenProvider;
|
||||
|
||||
public AuthenticationController(UserRepository userRepository, PasswordEncoder passwordEncoder, TokenProvider tokenProvider) {
|
||||
this.userRepository = userRepository;
|
||||
this.passwordEncoder = passwordEncoder;
|
||||
this.tokenProvider = tokenProvider;
|
||||
}
|
||||
|
||||
@PostMapping("/login")
|
||||
public LoginResponse login(@RequestBody LoginRequest request) {
|
||||
return userRepository.findByEmail(request.getEmail())
|
||||
.map(user -> checkCredentials(request, user))
|
||||
.map(LoginResponse::new)
|
||||
.orElseThrow(() -> new BadRequestException("MSG_INVALID_CREDENTIALS"));
|
||||
}
|
||||
|
||||
/**
|
||||
* If passwords match, this function generate a token. Otherwise, an {@link BadRequestException} is returned.
|
||||
*/
|
||||
private String checkCredentials(LoginRequest loginRequest, User user) {
|
||||
if (passwordEncoder.matches(loginRequest.getPassword(), user.getPassword())) {
|
||||
return tokenProvider.generateToken(user);
|
||||
} else {
|
||||
throw new BadRequestException("Invalid credentials");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package org.takiguchi.starter.exception;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
|
||||
public class BadRequestException extends BusinessException {
|
||||
public BadRequestException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public BadRequestException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package org.takiguchi.starter.exception;
|
||||
|
||||
/**
|
||||
* Business exception.
|
||||
*/
|
||||
public class BusinessException extends RuntimeException {
|
||||
|
||||
public BusinessException() {}
|
||||
|
||||
/**
|
||||
* Constructs an exception with a message.
|
||||
* @param message The description of the error met.
|
||||
*/
|
||||
public BusinessException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an exception with a message and a code.
|
||||
* @param message The description of the error met.
|
||||
* @param cause The cause of the exception.
|
||||
*/
|
||||
public BusinessException(final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.takiguchi.starter.exception;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
/**
|
||||
* Exception thrown when user attempt to access a resource that he has not rights.
|
||||
*/
|
||||
@ResponseStatus(value = HttpStatus.FORBIDDEN)
|
||||
public class ForbiddenException extends BusinessException {
|
||||
|
||||
public ForbiddenException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ForbiddenException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ForbiddenException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package org.takiguchi.starter.exception;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
public class InternalServerErrorException extends TechnicalException {
|
||||
public InternalServerErrorException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public InternalServerErrorException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package org.takiguchi.starter.exception;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
public class NoContentException extends BusinessException {
|
||||
public NoContentException() {}
|
||||
|
||||
public NoContentException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public NoContentException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package org.takiguchi.starter.exception;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@ResponseStatus(value = HttpStatus.NOT_FOUND)
|
||||
public class NotFoundException extends BusinessException {
|
||||
public NotFoundException() {}
|
||||
|
||||
public NotFoundException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public NotFoundException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.takiguchi.starter.exception;
|
||||
|
||||
/**
|
||||
* Technical exception.
|
||||
*/
|
||||
public class TechnicalException extends RuntimeException {
|
||||
/**
|
||||
* Constructs an exception with a message.
|
||||
* @param message The description of the error met.
|
||||
*/
|
||||
public TechnicalException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an exception with a message and a code.
|
||||
* @param message The description of the error met.
|
||||
* @param cause The cause of the exception.
|
||||
*/
|
||||
public TechnicalException(final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.takiguchi.starter.exception;
|
||||
|
||||
public class TournamentValidationException extends BusinessException {
|
||||
public TournamentValidationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.takiguchi.starter.exception;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
/**
|
||||
* Exception thrown when an anonymous user attempt to access to secured resource or if he failed to login.
|
||||
*/
|
||||
@ResponseStatus(value = HttpStatus.UNAUTHORIZED)
|
||||
public class UnauthorizedException extends BusinessException {
|
||||
public UnauthorizedException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public UnauthorizedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public UnauthorizedException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
26
src/main/java/org/takiguchi/starter/model/dao/User.java
Normal file
26
src/main/java/org/takiguchi/starter/model/dao/User.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package org.takiguchi.starter.model.dao;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
@Table(name = "`user`")
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public class User {
|
||||
@Id
|
||||
@GeneratedValue(generator = "system-uuid")
|
||||
private UUID id;
|
||||
@Column(nullable = false)
|
||||
private String email;
|
||||
@Column(nullable = false)
|
||||
private String password;
|
||||
private String username;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package org.takiguchi.starter.model.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter @Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class LoginRequest {
|
||||
private String email;
|
||||
private String password;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package org.takiguchi.starter.model.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class LoginResponse {
|
||||
private String token;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.takiguchi.starter.repository;
|
||||
|
||||
import org.takiguchi.starter.model.dao.User;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
@Repository
|
||||
public interface UserRepository extends JpaRepository<User, UUID> {
|
||||
Optional<User> findByEmail(String email);
|
||||
}
|
||||
36
src/main/resources/application.yml
Normal file
36
src/main/resources/application.yml
Normal file
@@ -0,0 +1,36 @@
|
||||
app:
|
||||
security:
|
||||
signing-key: SigningKeyValue!
|
||||
# 5 * 60 * 60 -> 5 hours
|
||||
access-token-validity-seconds: 18000
|
||||
|
||||
# =================================================
|
||||
# Spring configuration
|
||||
# =================================================
|
||||
spring:
|
||||
# -------------------------------------------------
|
||||
# Database configuration
|
||||
# -------------------------------------------------
|
||||
datasource:
|
||||
driverClassName: org.postgresql.Driver
|
||||
url: jdbc:postgresql://localhost:5432/db_database
|
||||
username: postgres
|
||||
password: postgres
|
||||
# Disable feature detection by this undocumented parameter.
|
||||
# Check the org.hibernate.engine.jdbc.internal.JdbcServiceImpl.configure method for more details.
|
||||
jpa:
|
||||
database-platform: org.hibernate.dialect.PostgreSQLDialect
|
||||
properties.hibernate.temp.use_jdbc_metadata_defaults: false
|
||||
open-in-view: false
|
||||
|
||||
server:
|
||||
error:
|
||||
whitelabel:
|
||||
enabled: false # Disable html error responses.
|
||||
|
||||
logging:
|
||||
level:
|
||||
org:
|
||||
# hibernate: DEBUG
|
||||
springframework:
|
||||
# mail: DEBUG
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.takiguchi.starter;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest
|
||||
class StarterApplicationTests {
|
||||
|
||||
@Test
|
||||
void contextLoads() {
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user