요구사항
전체적인 구성
config
WebSecurityConfig
package com.sparta.springboards.config;
import com.sparta.springboards.jwt.JwtAuthFilter;
import com.sparta.springboards.jwt.JwtUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.WebSecurityCustomizer;
import org.springframework.security.config.http.SessionCreationPolicy;
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.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@RequiredArgsConstructor
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class WebSecurityConfig {
private final JwtUtil jwtUtil;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring()
.requestMatchers(PathRequest.toH2Console())
.requestMatchers(PathRequest.toStaticResources().atCommonLocations());
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.authorizeRequests().antMatchers("/api/auth/**").permitAll()
// .antMatchers("/api/shop").permitAll()
//그 이외의 URL 요청들을 전부 다 authentication(인증 처리)하겠다
.anyRequest().authenticated()
// JWT 인증/인가를 사용하기 위한 설정
// Custom Filter 등록하기
//addFilterBefore: 어떤 Filter 이전에 추가하겠다 --> 우리가 만든 JwtAuthFilter 를 UsernamePasswordAuthenticationFilter 이전에 실행할 수 있도록
//1. JwtAuthFilter 를 통해 인증 객체를 만들고 --> 2. context 에 추가 --> 3.인증 완료 --> UsernamePasswordAuthenticationFilter 수행 --> 인증됐으므로 다음 Filter 로 이동 --> Controller 까지도 이동
.and().addFilterBefore(new JwtAuthFilter(jwtUtil), UsernamePasswordAuthenticationFilter.class);
// // Custom 로그인 페이지 사용
// // Security 에서 제공하는 default Form Login 을 사용하겠다
// http.formLogin().loginPage("/api/user/login-page").permitAll();
//"거부"가 났을 때, 403 Forbidden 페이지(접근 제한 페이지) 이동 설정
http.exceptionHandling().accessDeniedPage("/api/user/forbidden");
return http.build();
}
}
controller
BoardController
package com.sparta.springboards.controller;
import com.sparta.springboards.dto.BoardRequestDto;
import com.sparta.springboards.dto.BoardResponseDto;
import com.sparta.springboards.dto.MsgResponseDto;
import com.sparta.springboards.security.UserDetailsImpl;
import com.sparta.springboards.service.BoardService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequiredArgsConstructor
@RequestMapping("/api")
public class BoardController {
private final BoardService boardService;
@PostMapping("/post")
public BoardResponseDto createBoard(@RequestBody BoardRequestDto requestDto, @AuthenticationPrincipal UserDetailsImpl userDetails) {
return boardService.createBoard(requestDto, userDetails.getUser());
}
@GetMapping("/posts")
public List<BoardResponseDto> getListBoards() {
return boardService.getListBoards();
}
@GetMapping("/post/{id}")
public BoardResponseDto getBoards(@PathVariable Long id) {
return boardService.getBoard(id);
}
@PutMapping("/post/{id}")
public BoardResponseDto updateBoard(@PathVariable Long id, @RequestBody BoardRequestDto requestDto, @AuthenticationPrincipal UserDetailsImpl userDetails) {
return boardService.updateBoard(id, requestDto, userDetails.getUser());
}
@DeleteMapping("/post/{id}")
public MsgResponseDto deleteBoard(@PathVariable Long id, @AuthenticationPrincipal UserDetailsImpl userDetails) {
boardService.deleteBoard(id,userDetails.getUser());
return new MsgResponseDto("삭제 성공", HttpStatus.OK.value());
}
}
UserController
package com.sparta.springboards.controller;
import com.sparta.springboards.dto.LoginRequestDto;
import com.sparta.springboards.dto.MsgResponseDto;
import com.sparta.springboards.dto.SignupRequestDto;
import com.sparta.springboards.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
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.ResponseBody;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
@Controller
@RequiredArgsConstructor
@RequestMapping("/api/auth")
public class UserController {
private final UserService userService;
@PostMapping("/signup")
public ResponseEntity<MsgResponseDto> signup(@RequestBody @Valid SignupRequestDto signupRequestDto) {
userService.signup(signupRequestDto);
return ResponseEntity.ok(new MsgResponseDto("회원가입 완료", HttpStatus.OK.value()));
}
@ResponseBody
@PostMapping("/login")
public ResponseEntity<MsgResponseDto> login(@RequestBody LoginRequestDto loginRequestDto, HttpServletResponse response) {
userService.login(loginRequestDto, response);
return ResponseEntity.ok(new MsgResponseDto("로그인 완료",HttpStatus.OK.value()));
}
}
dto
BoardRequestDto
package com.sparta.springboards.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class BoardRequestDto {
private String title;
private String contents;
}
BoardResponseDto
package com.sparta.springboards.dto;
import com.sparta.springboards.entity.Board;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
@Getter
@NoArgsConstructor
public class BoardResponseDto {
private Long id;
private String title;
private String contents;
private String username;
private LocalDateTime createdAt;
private LocalDateTime modifiedAt;
public BoardResponseDto(Board board) {
this.id = board.getId();
this.title = board.getTitle();
this.contents = board.getContents();
this.username = board.getUsername();
this.createdAt = board.getCreatedAt();
this.modifiedAt = board.getModifiedAt();
}
}
LoginRequestDto
package com.sparta.springboards.dto;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
public class LoginRequestDto {
private String username;
private String password;
}
MsgResponseDto
package com.sparta.springboards.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class MsgResponseDto {
private String msg;
private int statusCode;
}
SecurityExceptionDto
package com.sparta.springboards.dto;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@NoArgsConstructor
public class SecurityExceptionDto {
private int statusCode;
private String msg;
public SecurityExceptionDto(int statusCode, String msg) {
this.statusCode = statusCode;
this.msg = msg;
}
}
SignupRequestDto
package com.sparta.springboards.dto;
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
@Setter
@Getter
public class SignupRequestDto {
@Size(min = 4,max = 10,message ="아이디는 4에서 10자 사이 입니다.")
@Pattern(regexp = "[a-z0-9]*$",message = "아이디 형식이 일치하지 않습니다.")
private String username;
@Size(min = 8,max = 15,message ="비밀번호는 8에서 15자 사이 입니다.")
@Pattern(regexp = "[a-zA-Z0-9`~!@#$%^&*()_=+|{};:,.<>/?]*$",message = "비밀번호 형식이 일치하지 않습니다.")
private String password;
private boolean admin = false;
private String adminToken = "";
}
entity
Board
package com.sparta.springboards.entity;
import com.sparta.springboards.dto.BoardRequestDto;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.persistence.*;
@Getter
@Setter
@Entity
@Table(name = "Board")
@NoArgsConstructor
public class Board extends Timestamped {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(nullable = false)
private String title;
@Column(nullable = false)
private String username;
@Column(nullable = false)
private String contents;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
public Board(BoardRequestDto requestDto, User user) {
this.title = requestDto.getTitle();
this.username = user.getUsername();
this.contents = requestDto.getContents();
this.user = user;
}
public void update(BoardRequestDto boardrequestDto) {
this.title = boardrequestDto.getTitle();
this.contents = boardrequestDto.getContents();
}
}
Timestamped
package com.sparta.springboards.entity;
import lombok.Getter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.Column;
import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import java.time.LocalDateTime;
@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public class Timestamped {
@CreatedDate
@Column(updatable = false)
private LocalDateTime createdAt;
@LastModifiedDate
@Column
private LocalDateTime modifiedAt;
}
User
package com.sparta.springboards.entity;
import lombok.Getter;
import lombok.NoArgsConstructor;
import javax.persistence.*;
@Getter
@NoArgsConstructor
@Entity(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(nullable = false, unique = true)
private String username;
@Column(nullable = false)
private String password;
@Column(nullable = false)
@Enumerated(value = EnumType.STRING)
private UserRoleEnum role;
public User(String username, String password, UserRoleEnum role) {
this.username = username;
this.password = password;
this.role = role;
}
}
UserRoleEnum
package com.sparta.springboards.entity;
public enum UserRoleEnum {
USER(Authority.USER),
ADMIN(Authority.ADMIN);
private final String authority;
UserRoleEnum(String authority) {
this.authority = authority;
}
public String getAuthority() {
return this.authority;
}
public static class Authority {
public static final String USER = "ROLE_USER";
public static final String ADMIN = "ROLE_ADMIN";
}
}
jwt
JwtAuthFilter
package com.sparta.springboards.jwt;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sparta.springboards.dto.SecurityExceptionDto;
import io.jsonwebtoken.Claims;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
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;
@Slf4j
@RequiredArgsConstructor
public class JwtAuthFilter extends OncePerRequestFilter {
private final JwtUtil jwtUtil;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String token = jwtUtil.resolveToken(request);
if(token != null) {
if(!jwtUtil.validateToken(token)){
jwtExceptionHandler(response, "Token Error", HttpStatus.UNAUTHORIZED.value());
return;
}
Claims info = jwtUtil.getUserInfoFromToken(token);
setAuthentication(info.getSubject());
}
filterChain.doFilter(request,response);
}
public void setAuthentication(String username) {
SecurityContext context = SecurityContextHolder.createEmptyContext();
Authentication authentication = jwtUtil.createAuthentication(username);
context.setAuthentication(authentication);
SecurityContextHolder.setContext(context);
}
public void jwtExceptionHandler(HttpServletResponse response, String msg, int statusCode) {
response.setStatus(statusCode);
response.setContentType("application/json");
try {
String json = new ObjectMapper().writeValueAsString(new SecurityExceptionDto(statusCode, msg));
response.getWriter().write(json);
} catch (Exception e) {
log.error(e.getMessage());
}
}
}
JwtUtil
package com.sparta.springboards.jwt;
import com.sparta.springboards.entity.UserRoleEnum;
import com.sparta.springboards.security.UserDetailsServiceImpl;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SecurityException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.security.Key;
import java.util.Base64;
import java.util.Date;
@Slf4j
@Component
@RequiredArgsConstructor
public class JwtUtil {
private final UserDetailsServiceImpl userDetailsService;
public static final String AUTHORIZATION_HEADER = "Authorization";
public static final String AUTHORIZATION_KEY = "auth";
private static final String BEARER_PREFIX = "Bearer ";
private static final long TOKEN_TIME = 60 * 60 * 1000L;
@Value("${jwt.secret.key}")
private String secretKey;
private Key key;
private final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
@PostConstruct
public void init() {
byte[] bytes = Base64.getDecoder().decode(secretKey);
key = Keys.hmacShaKeyFor(bytes);
}
public String resolveToken(HttpServletRequest request) {
String bearerToken = request.getHeader(AUTHORIZATION_HEADER);
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(BEARER_PREFIX)) {
return bearerToken.substring(7);
}
return null;
}
public String createToken(String username, UserRoleEnum role) {
Date date = new Date();
return BEARER_PREFIX +
Jwts.builder()
.setSubject(username)
.claim(AUTHORIZATION_KEY, role)
.setExpiration(new Date(date.getTime() + TOKEN_TIME))
.setIssuedAt(date)
.signWith(key, signatureAlgorithm)
.compact();
}
public boolean validateToken(String token) {
try {
Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token);
return true;
} catch (SecurityException | MalformedJwtException e) {
log.info("Invalid JWT signature, 유효하지 않는 JWT 서명 입니다.");
} catch (ExpiredJwtException e) {
log.info("Expired JWT token, 만료된 JWT token 입니다.");
} catch (UnsupportedJwtException e) {
log.info("Unsupported JWT token, 지원되지 않는 JWT 토큰 입니다.");
} catch (IllegalArgumentException e) {
log.info("JWT claims is empty, 잘못된 JWT 토큰 입니다.");
}
return false;
}
public Claims getUserInfoFromToken(String token) {
return Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token).getBody();
}
public Authentication createAuthentication(String username) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
}
}
repository
BoardRepository
package com.sparta.springboards.repository;
import com.sparta.springboards.entity.Board;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
import java.util.Optional;
public interface BoardRepository extends JpaRepository<Board, Long> {
List<Board> findAllByOrderByModifiedAtDesc();
Optional<Board> findByIdAndUserId(Long id, Long userId);
}
UserRepository
package com.sparta.springboards.repository;
import com.sparta.springboards.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByUsername(String username);
}
security
UserDetailsImpl
package com.sparta.springboards.security;
import com.sparta.springboards.entity.User;
import com.sparta.springboards.entity.UserRoleEnum;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.ArrayList;
import java.util.Collection;
public class UserDetailsImpl implements UserDetails {
private final User user;
private final String username;
public UserDetailsImpl(User user, String username) {
this.user = user;
this.username = username;
}
public User getUser() {
return user;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
UserRoleEnum role = user.getRole();
String authority = role.getAuthority();
SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(authority);
Collection<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(simpleGrantedAuthority);
return authorities;
}
@Override
public String getUsername() {
return this.username;
}
@Override
public String getPassword() {
return null;
}
@Override
public boolean isAccountNonExpired() {
return false;
}
@Override
public boolean isAccountNonLocked() {
return false;
}
@Override
public boolean isCredentialsNonExpired() {
return false;
}
@Override
public boolean isEnabled() {
return false;
}
}
UserDetailsServiceImpl
package com.sparta.springboards.security;
import com.sparta.springboards.entity.User;
import com.sparta.springboards.repository.UserRepository;
import lombok.RequiredArgsConstructor;
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;
@Service
@RequiredArgsConstructor
public class UserDetailsServiceImpl implements UserDetailsService {
private final UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("사용자를 찾을 수 없습니다."));
return new UserDetailsImpl(user, user.getUsername());
}
}
service
BoardService
package com.sparta.springboards.service;
import com.sparta.springboards.dto.BoardRequestDto;
import com.sparta.springboards.dto.BoardResponseDto;
import com.sparta.springboards.entity.Board;
import com.sparta.springboards.entity.User;
import com.sparta.springboards.entity.UserRoleEnum;
import com.sparta.springboards.jwt.JwtUtil;
import com.sparta.springboards.repository.BoardRepository;
import com.sparta.springboards.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
@Service
@RequiredArgsConstructor
public class BoardService {
private final BoardRepository boardRepository;
private final UserRepository userRepository;
private final JwtUtil jwtUtil;
@Transactional
public BoardResponseDto createBoard(BoardRequestDto requestDto, User user) {
Board board = boardRepository.save(new Board(requestDto, user));
return new BoardResponseDto(board);
}
@Transactional(readOnly = true)
public List<BoardResponseDto> getListBoards() {
List<Board> boardList = boardRepository.findAllByOrderByModifiedAtDesc();
List<BoardResponseDto> boardResponseDto = new ArrayList<>();
for (Board board : boardList) {
boardResponseDto.add(new BoardResponseDto(board));
}
return boardResponseDto;
}
@Transactional(readOnly = true)
public BoardResponseDto getBoard(Long id) {
Board board = boardRepository.findById(id).orElseThrow(
() -> new IllegalArgumentException("아이디가 존재하지 않습니다.")
);
return new BoardResponseDto(board);
}
@Transactional
public BoardResponseDto updateBoard(Long id, BoardRequestDto requestDto, User user) {
Board board;
if(user.getRole().equals(UserRoleEnum.ADMIN)) {
board = boardRepository.findById(id).orElseThrow(
() -> new IllegalArgumentException("게시글이 존재하지 않습니다.")
);
} else {
board = boardRepository.findByIdAndUserId(id, user.getId()).orElseThrow(
() -> new IllegalArgumentException("아이디가 존재하지 않습니다.")
);
}
board.update(requestDto);
return new BoardResponseDto(board);
}
@Transactional
public void deleteBoard (Long id, User user) {
Board board;
if(user.getRole().equals(UserRoleEnum.ADMIN)) {
board = boardRepository.findById(id).orElseThrow(
() -> new IllegalArgumentException("게시글이 존재하지 않습니다.")
);
} else {
board = boardRepository.findByIdAndUserId(id, user.getId()).orElseThrow(
() -> new IllegalArgumentException("아이디가 존재하지 않습니다.")
);
}
boardRepository.delete(board);
}
}
UserService
package com.sparta.springboards.service;
import com.sparta.springboards.dto.LoginRequestDto;
import com.sparta.springboards.dto.SignupRequestDto;
import com.sparta.springboards.entity.User;
import com.sparta.springboards.entity.UserRoleEnum;
import com.sparta.springboards.jwt.JwtUtil;
import com.sparta.springboards.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import javax.servlet.http.HttpServletResponse;
import java.util.Optional;
@Service
@Validated
@RequiredArgsConstructor
public class UserService {
private final UserRepository userRepository;
private final JwtUtil jwtUtil;
private final PasswordEncoder passwordEncoder;
private static final String ADMIN_TOKEN = "AAABnvxRVklrnYxKZ0aHgTBcXukeZygoC";
@Transactional
public void signup(SignupRequestDto signupRequestDto) {
String username = signupRequestDto.getUsername();
String password = passwordEncoder.encode(signupRequestDto.getPassword());
Optional<User> found = userRepository.findByUsername(username);
if (found.isPresent()) {
throw new IllegalArgumentException("중복된 사용자가 존재합니다.");
}
UserRoleEnum role = UserRoleEnum.USER;
if (signupRequestDto.isAdmin()) {
if (!signupRequestDto.getAdminToken().equals(ADMIN_TOKEN)) {
throw new IllegalArgumentException("관리자 암호가 틀려 등록이 불가능합니다.");
}
role = UserRoleEnum.ADMIN;
}
User user = new User(username, password, role);
userRepository.save(user);
}
@Transactional(readOnly = true)
public void login(LoginRequestDto loginRequestDto, HttpServletResponse response) {
String username = loginRequestDto.getUsername();
String password = loginRequestDto.getPassword();
User user = userRepository.findByUsername(username).orElseThrow(
() -> new IllegalArgumentException("등록된 사용자가 없습니다.")
);
if(!passwordEncoder.matches(password, user.getPassword())) {
throw new IllegalArgumentException("비밀번호가 일치하지 않습니다.");
}
response.addHeader(JwtUtil.AUTHORIZATION_HEADER, jwtUtil.createToken(user.getUsername(), user.getRole()));
}
}
application.properties
spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:db;MODE=MYSQL;
spring.datasource.username=sa
spring.datasource.password=
spring.thymeleaf.cache=false
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.format_sql=true
jwt.secret.key=7ZWt7ZW0OTntmZTsnbTtjIXtlZzqta3snYTrhIjrqLjshLjqs4TroZzrgpjslYTqsIDsnpDtm4zrpa3tlZzqsJzrsJzsnpDrpbzrp4zrk6TslrTqsIDsnpA=
logging.level.org.springframework=debug
logging.level.org.springframework.web=debug
build.gradle
plugins {
id 'java'
id 'org.springframework.boot' version '2.7.6'
id 'io.spring.dependency-management' version '1.0.15.RELEASE'
}
group = 'com.sparta'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.h2database:h2'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
implementation group: 'org.json', name: 'json', version: '20220924'
compileOnly group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.11.2'
runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.2'
runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.2'
implementation 'org.springframework.boot:spring-boot-starter-validation'
}
tasks.named('test') {
useJUnitPlatform()
}