[SpringBoot] 프로젝트 생성기

윤경·2021년 10월 15일
0

Spring Boot

목록 보기
41/79


CodeView

:

기능(임시)
  • 로그인
  • 게시판

프로젝트 생성


구조


코드

학습했던 수업에서 구현했던 로그인과는 달리 Spring Security를 활용해 로그인을 구현

Spring Security: 스프링 기반 애플리케이션 보안을 담당하는 프레임워크
사용자 인증, 권한, 보안 처리를 간단하지만 강력하게 구현할 수 있다.

auth

✔️ MyUserDetail

package codebook.codeview.auth;

import codebook.codeview.entity.User;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
//import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;
import java.util.Collections;

public class MyUserDetail implements UserDetails {
    private String email;
    private String password;
    private String auth;

    public MyUserDetail(User user) {
        this.email = user.getEmail();
        this.password = user.getPassword();
        this.auth = "ROLE_" + user.getRole();
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return Collections.singletonList(new SimpleGrantedAuthority(this.auth));
    }

    @Override
    public String getPassword() {
        return this.password;
    }

    @Override
    public String getUsername() {
        return this.email;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

✔️ SecurityConfig

package codebook.codeview.auth;

import codebook.codeview.service.UserService;
import lombok.RequiredArgsConstructor;
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.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@EnableWebSecurity        //spring security 를 적용한다는 Annotation
@RequiredArgsConstructor
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    private final UserService exService;
    /**
     * 규칙 설정
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/welcome").hasRole("USER")
                .antMatchers("/signup").anonymous()
                .and()
                .formLogin()
                .and()
                .csrf().disable();		//로그인 창
    }

    /**
     * 로그인 인증 처리 메소드
     * @param auth
     * @throws Exception
     */
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(exService).passwordEncoder(new BCryptPasswordEncoder());
    }
}

controller

✔️ UserController

package codebook.codeview.controller;

import codebook.codeview.auth.MyUserDetail;
import codebook.codeview.entity.User;
import codebook.codeview.service.UserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
//import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

import javax.servlet.ServletException;
import java.io.IOException;

@Controller
@RequiredArgsConstructor
@Slf4j
public class UserController {
    private final UserService service;

    /**
     * 회원가입 폼
     * @return
     */
    @GetMapping("/signup")
    public String signupForm() {
        return "signup";
    }

    /**
     * 회원가입 진행
     * @param user
     * @return
     */
    @PostMapping("/signup")
    public String signup(User user) {
        user.setRole("USER");
        service.joinUser(user);
        return "redirect:/check";
    }

//    @PostMapping("/signUp")
//    public String signUp(User user) {
//        user.setRole("USER");
//        service.joinUser(user);
//        return "redirect:/check";
//    }

    /**
     * 유저 페이지
     * @param model
     * @param authentication
     * @return
     */
    @GetMapping("/")
    public String userAccess(Model model, Authentication authentication) {
        //Authentication 객체를 통해 유저 정보를 가져올 수 있다.
        MyUserDetail userDetail = (MyUserDetail)authentication.getPrincipal();  //userDetail 객체를 가져옴
        model.addAttribute("info", userDetail.getUsername());      //유저 이메일
        return "welcome";
    }
}

entity

✔️ User

package codebook.codeview.entity;

import lombok.Getter;
import lombok.Setter;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
@Getter
@Setter
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String email;    //이메일
    private String password; //패스워드
    private String role;     //권한
}

repository

✔️ UserRepository

package codebook.codeview.repository;

import codebook.codeview.entity.User;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;

@Repository
@RequiredArgsConstructor
public class UserRepository {
    private final EntityManager em;

    public void saveUser(User user){
        em.persist(user);
    }

    public User findUserByEmail(String email){
        TypedQuery<User> query = em.createQuery("select m from User as m where m.email = ?1", User.class)
                .setParameter(1, email);
        return query.getSingleResult();
    }
}

service

✔️ UserService

package codebook.codeview.service;

import codebook.codeview.auth.MyUserDetail;
import codebook.codeview.entity.User;
import codebook.codeview.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
//import org.springframework.security.core.userdetails.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;

@Service
@RequiredArgsConstructor
@Slf4j
public class UserService implements UserDetailsService {

//    @Autowired
    private final UserRepository repository;

    @Transactional
    public void joinUser(User user){
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        repository.saveUser(user);
    }

    @Override
    public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
        //여기서 받은 유저 패스워드와 비교하여 로그인 인증
        User user = repository.findUserByEmail(email);
        return new MyUserDetail(user);
    }

}

resources/templates

✔️ check.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>TEST!!!!!!!!</title>
</head>
<body>
TEST!!!!!!!!!!!
</body>
</html>

✔️ signup.html

<!--회원가입 페이지-->
<!--signup.html-->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head>
    <meta charset="UTF-8">
</head>
<body>
<form method="post" action="/signup">
    email : <input type="email" name="email">
    password : <input type="password" name="password">
    <button>회원가입</button>
</form>
</body>
</html>

✔️ welcome.html

<!--유저 페이지-->
<!--user_access.html-->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head>
    <meta charset="UTF-8">
    <title>user access</title>
</head>
<body>
<span>환영합니다</span>
<p th:text="${info}"></p>
</body>
</html>

✔️ resources/application.yml

spring:
  datasource:
    driver-class-name: org.h2.Driver
    url: jdbc:h2:tcp://localhost/~/codeview
    username: sa
    password:

  jpa:
    hibernate:
      #옵션 create, update, none, create-drop, validate 있음
      ddl-auto: none
    properties:
      hibernate:
        format_sql: true

logging:
  level:
    org:hibernate:SQL: DEBUG

✔️ build.gradle

plugins {
	id 'org.springframework.boot' version '2.5.5'
	id 'io.spring.dependency-management' version '1.0.11.RELEASE'
	id 'java'
}

group = 'codebook'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

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'
	compileOnly 'org.projectlombok:lombok'
	runtimeOnly 'com.h2database:h2'
//	compileOnly 'com.h2database:h2'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

test {
	useJUnitPlatform()
}

H2

참고와는 다르게 sql을 h2를 사용


실행

http://localhost:8080/ 를 실행시켰을 때 에러

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause

http://localhost:8080/signup

signup 에러

SQL Error: 23502, SQLState: 23502

NULL not allowed for column "ID"; SQL statement:
insert into user (id, email, password, role) values (null, ?, ?, ?) [23502-200]

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement] with root cause

테이블을 생성해보고 H2로 SQL 설정도 바꾸고 애노테이션도 몇개 추가해보았지만 해결하지 못함


오늘은 에러를 미처 해결하지 못했다.

후회하는 점:
maven이 아닌 gradle으로 프로젝트를 생성한 것.
MySQL이 아닌 H2를 사용한 것.

내가 Spring Security를 잘 모른다는 점..


Security 참고

profile
개발 바보 이사 중

0개의 댓글