From a8426d3a3e66e0dc1f0dc154685b7416a402ed78 Mon Sep 17 00:00:00 2001 From: "Shin, Jeongbin" Date: Wed, 14 Dec 2022 14:59:20 +0900 Subject: [PATCH 01/11] init --- docker-compose.yml | 11 +- pom.xml | 34 ++++++ .../user/controller/LoginController.java | 75 +++++++++++++ .../badgeroad/user/dto/MemberDto.java | 25 +++++ .../badgeroad/user/dto/MemberLoginDto.java | 11 ++ .../user/dto/MemberSignupRequestDto.java | 12 +++ .../badgeroad/user/entity/Member.java | 41 +++++++ .../hotnerds/badgeroad/user/entity/Role.java | 28 +++++ .../user/repository/MemberRepository.java | 9 ++ .../user/repository/RoleRepository.java | 8 ++ .../badgeroad/user/service/MemberService.java | 17 +++ .../user/service/MemberServiceImpl.java | 77 +++++++++++++ src/main/resources/application-api.yml | 0 src/main/resources/application.yml | 10 ++ src/main/resources/templates/login.html | 102 ++++++++++++++++++ .../templates/login/config/CorsConfig.java | 23 ++++ .../login/config/SecurityConfig.java | 89 +++++++++++++++ .../login/controller/AuthController.java | 58 ++++++++++ .../login/controller/UserController.java | 56 ++++++++++ .../templates/login/dto/AuthorityDto.java | 12 +++ .../templates/login/dto/ErrorDto.java | 34 ++++++ .../templates/login/dto/LoginDto.java | 22 ++++ .../templates/login/dto/TokenDto.java | 13 +++ .../templates/login/dto/UserDto.java | 45 ++++++++ .../templates/login/entity/Authority.java | 22 ++++ .../templates/login/entity/User.java | 40 +++++++ .../exception/DuplicateMemberException.java | 16 +++ .../exception/NotFoundMemberException.java | 16 +++ ...ethodArgumentNotValidExceptionHandler.java | 37 +++++++ .../handler/RestResponseExceptionHandler.java | 33 ++++++ .../login/jwt/JwtAccessDeniedHandler.java | 18 ++++ .../jwt/JwtAuthenticationEntryPoint.java | 20 ++++ .../templates/login/jwt/JwtFilter.java | 52 +++++++++ .../login/jwt/JwtSecurityConfig.java | 21 ++++ .../templates/login/jwt/TokenProvider.java | 94 ++++++++++++++++ .../login/repository/AuthorityRepository.java | 7 ++ .../login/repository/UserRepository.java | 12 +++ .../service/CustomUserDetailsService.java | 45 ++++++++ .../templates/login/service/UserService.java | 60 +++++++++++ .../templates/login/util/SecurityUtil.java | 35 ++++++ src/main/resources/templates/main.html | 13 +++ 41 files changed, 1352 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/hotnerds/badgeroad/user/controller/LoginController.java create mode 100644 src/main/java/com/hotnerds/badgeroad/user/dto/MemberDto.java create mode 100644 src/main/java/com/hotnerds/badgeroad/user/dto/MemberLoginDto.java create mode 100644 src/main/java/com/hotnerds/badgeroad/user/dto/MemberSignupRequestDto.java create mode 100644 src/main/java/com/hotnerds/badgeroad/user/entity/Member.java create mode 100644 src/main/java/com/hotnerds/badgeroad/user/entity/Role.java create mode 100644 src/main/java/com/hotnerds/badgeroad/user/repository/MemberRepository.java create mode 100644 src/main/java/com/hotnerds/badgeroad/user/repository/RoleRepository.java create mode 100644 src/main/java/com/hotnerds/badgeroad/user/service/MemberService.java create mode 100644 src/main/java/com/hotnerds/badgeroad/user/service/MemberServiceImpl.java create mode 100644 src/main/resources/application-api.yml create mode 100644 src/main/resources/templates/login.html create mode 100644 src/main/resources/templates/login/config/CorsConfig.java create mode 100644 src/main/resources/templates/login/config/SecurityConfig.java create mode 100644 src/main/resources/templates/login/controller/AuthController.java create mode 100644 src/main/resources/templates/login/controller/UserController.java create mode 100644 src/main/resources/templates/login/dto/AuthorityDto.java create mode 100644 src/main/resources/templates/login/dto/ErrorDto.java create mode 100644 src/main/resources/templates/login/dto/LoginDto.java create mode 100644 src/main/resources/templates/login/dto/TokenDto.java create mode 100644 src/main/resources/templates/login/dto/UserDto.java create mode 100644 src/main/resources/templates/login/entity/Authority.java create mode 100644 src/main/resources/templates/login/entity/User.java create mode 100644 src/main/resources/templates/login/exception/DuplicateMemberException.java create mode 100644 src/main/resources/templates/login/exception/NotFoundMemberException.java create mode 100644 src/main/resources/templates/login/handler/MethodArgumentNotValidExceptionHandler.java create mode 100644 src/main/resources/templates/login/handler/RestResponseExceptionHandler.java create mode 100644 src/main/resources/templates/login/jwt/JwtAccessDeniedHandler.java create mode 100644 src/main/resources/templates/login/jwt/JwtAuthenticationEntryPoint.java create mode 100644 src/main/resources/templates/login/jwt/JwtFilter.java create mode 100644 src/main/resources/templates/login/jwt/JwtSecurityConfig.java create mode 100644 src/main/resources/templates/login/jwt/TokenProvider.java create mode 100644 src/main/resources/templates/login/repository/AuthorityRepository.java create mode 100644 src/main/resources/templates/login/repository/UserRepository.java create mode 100644 src/main/resources/templates/login/service/CustomUserDetailsService.java create mode 100644 src/main/resources/templates/login/service/UserService.java create mode 100644 src/main/resources/templates/login/util/SecurityUtil.java create mode 100644 src/main/resources/templates/main.html diff --git a/docker-compose.yml b/docker-compose.yml index 65e33c4..6ab31a3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,9 +5,18 @@ services: command: --default-authentication-plugin=mysql_native_password restart: always ports: +<<<<<<< Updated upstream - '3306:3306' environment: MYSQL_ROOT_PASSWORD: badgeload MYSQL_DATABASE: badgeload MYSQL_USER: badgeload - MYSQL_PASSWORD: badgeload \ No newline at end of file + MYSQL_PASSWORD: badgeload +======= + - 3306:3306 + environment: + MYSQL_ROOT_PASSWORD: badgeroad + MYSQL_DATABASE: badgeroad + MYSQL_USER: badgeroad + MYSQL_PASSWORD: password +>>>>>>> Stashed changes diff --git a/pom.xml b/pom.xml index 64387ab..33fc729 100644 --- a/pom.xml +++ b/pom.xml @@ -51,6 +51,40 @@ spring-boot-starter-test test +<<<<<<< Updated upstream +======= + + com.googlecode.json-simple + json-simple + 1.1.1 + + + + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + io.jsonwebtoken + jjwt-api + 0.11.5 + + + io.jsonwebtoken + jjwt-impl + 0.11.5 + runtime + + + io.jsonwebtoken + jjwt-jackson + 0.11.5 + runtime + +>>>>>>> Stashed changes diff --git a/src/main/java/com/hotnerds/badgeroad/user/controller/LoginController.java b/src/main/java/com/hotnerds/badgeroad/user/controller/LoginController.java new file mode 100644 index 0000000..5b5bb14 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/user/controller/LoginController.java @@ -0,0 +1,75 @@ +package com.hotnerds.badgeroad.user.controller; + +import com.hotnerds.badgeroad.user.dto.MemberDto; +import com.hotnerds.badgeroad.user.entity.Member; +import com.hotnerds.badgeroad.user.service.MemberService; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; + +@Controller +@RequestMapping("/user") +public class LoginController { + private final MemberService memberService; + + public LoginController(MemberService memberService) { + this.memberService = memberService; + } + + @GetMapping("/login") + public String loginForm() { + return "login"; + } + + @GetMapping("/signup") + public String showRegistrationForm(Model model){ + MemberDto member = new MemberDto(); + model.addAttribute("member", member); + return "signup"; + } + + @GetMapping("/common") + public String common() { + return "common"; + } + + + + @PostMapping("/login") + public String loginConfirm(@ModelAttribute("Member") MemberDto member, + BindingResult result, + Model model) { + return "redirect:/main"; + } + + // handler method to handle Member registration request + + + // handler method to handle register Member form submit request + @PostMapping("/signup") + public String registration(@Valid @ModelAttribute("Member") MemberDto member, + BindingResult result, + Model model){ + Member existing = memberService.findByEmail(member.getEmail()); + if (existing != null) { + result.rejectValue("email", null, "There is already an account registered with that email"); + } + if (result.hasErrors()) { + model.addAttribute("member", member); + return "signup"; + } + memberService.saveMember(member); + return "good"; + } + + @GetMapping("/members") + public String listRegisteredMembers(Model model){ + List members = memberService.findAllMembers(); + model.addAttribute("Members", members); + return "members"; + } +} diff --git a/src/main/java/com/hotnerds/badgeroad/user/dto/MemberDto.java b/src/main/java/com/hotnerds/badgeroad/user/dto/MemberDto.java new file mode 100644 index 0000000..b366163 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/user/dto/MemberDto.java @@ -0,0 +1,25 @@ +package com.hotnerds.badgeroad.user.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import javax.validation.constraints.Email; +import javax.validation.constraints.NotEmpty; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class MemberDto +{ + private Long id; + @NotEmpty(message = "Email should not be empty") + @Email + private String email; + @NotEmpty(message = "Password should not be empty") + private String password; + @NotEmpty(message = "name should not be empty") + private String name; +} \ No newline at end of file diff --git a/src/main/java/com/hotnerds/badgeroad/user/dto/MemberLoginDto.java b/src/main/java/com/hotnerds/badgeroad/user/dto/MemberLoginDto.java new file mode 100644 index 0000000..dd84c77 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/user/dto/MemberLoginDto.java @@ -0,0 +1,11 @@ +package com.hotnerds.badgeroad.user.dto; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class MemberLoginDto { + private String email; + private String password; +} diff --git a/src/main/java/com/hotnerds/badgeroad/user/dto/MemberSignupRequestDto.java b/src/main/java/com/hotnerds/badgeroad/user/dto/MemberSignupRequestDto.java new file mode 100644 index 0000000..5ea3d23 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/user/dto/MemberSignupRequestDto.java @@ -0,0 +1,12 @@ +package com.hotnerds.badgeroad.user.dto; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class MemberSignupRequestDto { + private String email; + private String password; + private String name; +} diff --git a/src/main/java/com/hotnerds/badgeroad/user/entity/Member.java b/src/main/java/com/hotnerds/badgeroad/user/entity/Member.java new file mode 100644 index 0000000..4887436 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/user/entity/Member.java @@ -0,0 +1,41 @@ +package com.hotnerds.badgeroad.user.entity; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import javax.persistence.*; +import java.util.ArrayList; +import java.util.List; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "member") +public class Member { + + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable=false) + private String name; + + @Column(nullable=false, unique=true) + private String email; + + @Column(nullable=false) + private String password; + + @ManyToMany(fetch = FetchType.EAGER, cascade=CascadeType.ALL) + @JoinTable( + name="member_role", + joinColumns={@JoinColumn(name="MEMBER_ID", referencedColumnName="ID")}, + inverseJoinColumns={@JoinColumn(name="ROLE_ID", referencedColumnName="ID")}) + private List roles = new ArrayList<>(); +} diff --git a/src/main/java/com/hotnerds/badgeroad/user/entity/Role.java b/src/main/java/com/hotnerds/badgeroad/user/entity/Role.java new file mode 100644 index 0000000..6b0993f --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/user/entity/Role.java @@ -0,0 +1,28 @@ +package com.hotnerds.badgeroad.user.entity; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import javax.persistence.*; +import java.util.List; + +@Setter +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name="role") +public class Role +{ + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable=false, unique=true) + private String name; + + @ManyToMany(mappedBy="roles") + private List members; +} diff --git a/src/main/java/com/hotnerds/badgeroad/user/repository/MemberRepository.java b/src/main/java/com/hotnerds/badgeroad/user/repository/MemberRepository.java new file mode 100644 index 0000000..f377587 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/user/repository/MemberRepository.java @@ -0,0 +1,9 @@ +package com.hotnerds.badgeroad.user.repository; + +import com.hotnerds.badgeroad.user.entity.Member; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface MemberRepository extends JpaRepository { + + Member findByEmail(String email); +} diff --git a/src/main/java/com/hotnerds/badgeroad/user/repository/RoleRepository.java b/src/main/java/com/hotnerds/badgeroad/user/repository/RoleRepository.java new file mode 100644 index 0000000..6ae104b --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/user/repository/RoleRepository.java @@ -0,0 +1,8 @@ +package com.hotnerds.badgeroad.user.repository; + +import com.hotnerds.badgeroad.user.entity.Role; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface RoleRepository extends JpaRepository { + Role findByName(String name); +} diff --git a/src/main/java/com/hotnerds/badgeroad/user/service/MemberService.java b/src/main/java/com/hotnerds/badgeroad/user/service/MemberService.java new file mode 100644 index 0000000..18f1106 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/user/service/MemberService.java @@ -0,0 +1,17 @@ +package com.hotnerds.badgeroad.user.service; + +import com.hotnerds.badgeroad.user.dto.MemberDto; +import com.hotnerds.badgeroad.user.dto.MemberLoginDto; +import com.hotnerds.badgeroad.user.entity.Member; + +import java.util.List; + +public interface MemberService { + void saveMember(MemberDto memberDto); + + Member findByEmail(String email); + + List findAllMembers(); + + Boolean loginConfirm(MemberLoginDto memberLoginDto); +} \ No newline at end of file diff --git a/src/main/java/com/hotnerds/badgeroad/user/service/MemberServiceImpl.java b/src/main/java/com/hotnerds/badgeroad/user/service/MemberServiceImpl.java new file mode 100644 index 0000000..b788cb9 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/user/service/MemberServiceImpl.java @@ -0,0 +1,77 @@ +package com.hotnerds.badgeroad.user.service; + +import com.hotnerds.badgeroad.user.dto.MemberDto; +import com.hotnerds.badgeroad.user.dto.MemberLoginDto; +import com.hotnerds.badgeroad.user.entity.Member; +import com.hotnerds.badgeroad.user.entity.Role; +import com.hotnerds.badgeroad.user.repository.MemberRepository; +import com.hotnerds.badgeroad.user.repository.RoleRepository; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +@AllArgsConstructor +public class MemberServiceImpl implements MemberService { + + private MemberRepository memberRepository; + private RoleRepository roleRepository; + +// public MemberServiceImpl(MemberRepository MemberRepository, +// RoleRepository roleRepository, +// PasswordEncoder passwordEncoder) { +// this.MemberRepository = MemberRepository; +// this.roleRepository = roleRepository; +// this.passwordEncoder = passwordEncoder; +// } + + @Override + public void saveMember(MemberDto MemberDto) { + Member member = new Member(); + member.setName(MemberDto.getName()); + member.setEmail(MemberDto.getEmail()); + + //encrypt the password once we integrate spring security + //Member.setPassword(MemberDto.getPassword()); + member.setPassword(MemberDto.getPassword()); + Role role = roleRepository.findByName("ROLE_ADMIN"); + if (role == null) { + role = checkRoleExist(); + } + member.setRoles(List.of(role)); + memberRepository.save(member); + } + + @Override + public Member findByEmail(String email) { + return memberRepository.findByEmail(email); + } + + @Override + public List findAllMembers() { + List members = memberRepository.findAll(); + return members.stream().map(this::convertEntityToDto) + .collect(Collectors.toList()); + } + + @Override + public Boolean loginConfirm(MemberLoginDto memberLoginDto) { + Member member = memberRepository.findByEmail(memberLoginDto.getEmail()); + return member.getPassword().equals(memberLoginDto.getPassword()); + } + + private MemberDto convertEntityToDto(Member member) { + MemberDto memberDto = new MemberDto(); + memberDto.setName(member.getName()); + memberDto.setEmail(member.getEmail()); + return memberDto; + } + + private Role checkRoleExist() { + Role role = new Role(); + role.setName("ROLE_ADMIN"); + return roleRepository.save(role); + } +} \ No newline at end of file diff --git a/src/main/resources/application-api.yml b/src/main/resources/application-api.yml new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 619e1ed..fcebc01 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -30,6 +30,16 @@ logging: level: org: hibernate: info +<<<<<<< Updated upstream +======= +# +#jwt: +# header: Authorization +# #HS512 알고리즘을 사용할 것이기 때문에 512bit, 즉 64byte 이상의 secret key를 사용해야 한다. +# #echo 'silvernine-tech-spring-boot-jwt-tutorial-secret-silvernine-tech-spring-boot-jwt-tutorial-secret'|base64 +# secret: c2lsdmVybmluZS10ZWNoLXNwcmluZy1ib290LWp3dC10dXRvcmlhbC1zZWNyZXQtc2lsdmVybmluZS10ZWNoLXNwcmluZy1ib290LWp3dC10dXRvcmlhbC1zZWNyZXQK +# token-validity-in-seconds: 86400 +>>>>>>> Stashed changes naver: url: diff --git a/src/main/resources/templates/login.html b/src/main/resources/templates/login.html new file mode 100644 index 0000000..ddc455e --- /dev/null +++ b/src/main/resources/templates/login.html @@ -0,0 +1,102 @@ + + + + + + + LOGIN + + +

HOME

+

LOGIN

+

SIGNUP

+ +
+
+ + +
+
+ + +
+
+ + Not registered? + Register/SignUp Here + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/login/config/CorsConfig.java b/src/main/resources/templates/login/config/CorsConfig.java new file mode 100644 index 0000000..cd1f656 --- /dev/null +++ b/src/main/resources/templates/login/config/CorsConfig.java @@ -0,0 +1,23 @@ +package templates.login.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; + +@Configuration +public class CorsConfig { + @Bean + public CorsFilter corsFilter() { + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + CorsConfiguration config = new CorsConfiguration(); + config.setAllowCredentials(true); + config.addAllowedOrigin("*"); + config.addAllowedHeader("*"); + config.addAllowedMethod("*"); + + source.registerCorsConfiguration("/api/**", config); + return new CorsFilter(source); + } +} diff --git a/src/main/resources/templates/login/config/SecurityConfig.java b/src/main/resources/templates/login/config/SecurityConfig.java new file mode 100644 index 0000000..c8f7c52 --- /dev/null +++ b/src/main/resources/templates/login/config/SecurityConfig.java @@ -0,0 +1,89 @@ +package templates.login.config; + +import com.hotnerds.badgeroad.user.jwt.JwtAccessDeniedHandler; +import com.hotnerds.badgeroad.user.jwt.JwtAuthenticationEntryPoint; +import com.hotnerds.badgeroad.user.jwt.JwtSecurityConfig; +import com.hotnerds.badgeroad.user.jwt.TokenProvider; +import org.springframework.context.annotation.Bean; +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; +import org.springframework.web.filter.CorsFilter; + +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true) +public class SecurityConfig { + private final TokenProvider tokenProvider; + private final CorsFilter corsFilter; + private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; + private final JwtAccessDeniedHandler jwtAccessDeniedHandler; + + public SecurityConfig( + TokenProvider tokenProvider, + CorsFilter corsFilter, + JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint, + JwtAccessDeniedHandler jwtAccessDeniedHandler + ) { + this.tokenProvider = tokenProvider; + this.corsFilter = corsFilter; + this.jwtAuthenticationEntryPoint = jwtAuthenticationEntryPoint; + this.jwtAccessDeniedHandler = jwtAccessDeniedHandler; + } + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Bean + public WebSecurityCustomizer webSecurityCustomizer() { + return (web) -> web.ignoring().antMatchers("/h2-console/**" + , "/favicon.ico" + , "/error"); + } + + @Bean + public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { + httpSecurity + // token을 사용하는 방식이기 때문에 csrf를 disable합니다. + .csrf().disable() + + .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class) + + .exceptionHandling() + .authenticationEntryPoint(jwtAuthenticationEntryPoint) + .accessDeniedHandler(jwtAccessDeniedHandler) + + // enable h2-console + .and() + .headers() + .frameOptions() + .sameOrigin() + + // 세션을 사용하지 않기 때문에 STATELESS로 설정 + .and() + .sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.STATELESS) + + .and() + .authorizeRequests() + .antMatchers("/").permitAll() + .antMatchers("/user/**").permitAll() + .antMatchers("/api/hello").permitAll() + .antMatchers("/api/authenticate").permitAll() + .antMatchers("/api/signup").permitAll() + + .anyRequest().authenticated() + + .and() + .apply(new JwtSecurityConfig(tokenProvider)); + + return httpSecurity.build(); + } +} \ No newline at end of file diff --git a/src/main/resources/templates/login/controller/AuthController.java b/src/main/resources/templates/login/controller/AuthController.java new file mode 100644 index 0000000..6cddd55 --- /dev/null +++ b/src/main/resources/templates/login/controller/AuthController.java @@ -0,0 +1,58 @@ +package templates.login.controller; + +import com.hotnerds.badgeroad.user.dto.MemberLoginDto; +import com.hotnerds.badgeroad.user.dto.TokenDto; +import com.hotnerds.badgeroad.user.jwt.JwtFilter; +import com.hotnerds.badgeroad.user.jwt.TokenProvider; +import org.springframework.http.HttpHeaders; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +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 javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.util.HashMap; +import java.util.Map; + +@RestController +@RequestMapping("/api") +public class AuthController { + private final TokenProvider tokenProvider; + private final AuthenticationManagerBuilder authenticationManagerBuilder; + + public AuthController(TokenProvider tokenProvider, AuthenticationManagerBuilder authenticationManagerBuilder) { + this.tokenProvider = tokenProvider; + this.authenticationManagerBuilder = authenticationManagerBuilder; + } + + @PostMapping("/authenticate") + public String authorize(@Valid @RequestBody MemberLoginDto memberLoginDto, HttpServletResponse response) { + + UsernamePasswordAuthenticationToken authenticationToken = + new UsernamePasswordAuthenticationToken(memberLoginDto.getUsername(), memberLoginDto.getPassword()); + + Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken); + SecurityContextHolder.getContext().setAuthentication(authentication); + + String jwt = tokenProvider.createToken(authentication); + + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.add(JwtFilter.AUTHORIZATION_HEADER, "Bearer " + jwt); + + Map user = new HashMap<>(); + user.put("id", memberLoginDto.getUsername()); + +// Cookie cookie = new Cookie( +// LoginCheck.COOKIE_NAME, +// jwtService.token(user, Optional.of(LocalDateTime.now().plusMinutes(30))) +// ); + + return "main"; +// return new ResponseEntity<>(new TokenDto(jwt), httpHeaders, HttpStatus.OK); + } +} diff --git a/src/main/resources/templates/login/controller/UserController.java b/src/main/resources/templates/login/controller/UserController.java new file mode 100644 index 0000000..bf82b1b --- /dev/null +++ b/src/main/resources/templates/login/controller/UserController.java @@ -0,0 +1,56 @@ +package templates.login.controller; + +import com.hotnerds.badgeroad.user.dto.UserDto; +import com.hotnerds.badgeroad.user.service.UserService; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; + +@RestController +@RequestMapping("/api") +public class UserController { + private final UserService userService; + + public UserController(UserService userService) { + this.userService = userService; + } + + @GetMapping("/") + public String index() { + return "index"; + } + + @GetMapping("/hello") + public ResponseEntity hello() { + return ResponseEntity.ok("hello"); + } + + @PostMapping("/test-redirect") + public void testRedirect(HttpServletResponse response) throws IOException { + response.sendRedirect("/api/user"); + } + + @PostMapping("/signup") + public ResponseEntity signup( + @Valid @RequestBody UserDto userDto + ) { + return ResponseEntity.ok(userService.signup(userDto)); + } + + @GetMapping("/user") + @PreAuthorize("hasAnyRole('USER','ADMIN')") + public ResponseEntity getMyUserInfo(HttpServletRequest request) { + return ResponseEntity.ok(userService.getMyUserWithAuthorities()); + } + + @GetMapping("/user/{username}") + @PreAuthorize("hasAnyRole('ADMIN')") + public ResponseEntity getUserInfo(@PathVariable String username) { + return ResponseEntity.ok(userService.getUserWithAuthorities(username)); + } +} diff --git a/src/main/resources/templates/login/dto/AuthorityDto.java b/src/main/resources/templates/login/dto/AuthorityDto.java new file mode 100644 index 0000000..1dd5a86 --- /dev/null +++ b/src/main/resources/templates/login/dto/AuthorityDto.java @@ -0,0 +1,12 @@ +package templates.login.dto; + +import lombok.*; + +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class AuthorityDto { + private String authorityName; +} \ No newline at end of file diff --git a/src/main/resources/templates/login/dto/ErrorDto.java b/src/main/resources/templates/login/dto/ErrorDto.java new file mode 100644 index 0000000..12f3104 --- /dev/null +++ b/src/main/resources/templates/login/dto/ErrorDto.java @@ -0,0 +1,34 @@ +package templates.login.dto; + +import org.springframework.validation.FieldError; + +import java.util.ArrayList; +import java.util.List; + +public class ErrorDto { + private final int status; + private final String message; + private List fieldErrors = new ArrayList<>(); + + public ErrorDto(int status, String message) { + this.status = status; + this.message = message; + } + + public int getStatus() { + return status; + } + + public String getMessage() { + return message; + } + + public void addFieldError(String objectName, String path, String message) { + FieldError error = new FieldError(objectName, path, message); + fieldErrors.add(error); + } + + public List getFieldErrors() { + return fieldErrors; + } +} diff --git a/src/main/resources/templates/login/dto/LoginDto.java b/src/main/resources/templates/login/dto/LoginDto.java new file mode 100644 index 0000000..671b7b0 --- /dev/null +++ b/src/main/resources/templates/login/dto/LoginDto.java @@ -0,0 +1,22 @@ +package templates.login.dto; + +import lombok.*; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class LoginDto { + + @NotNull + @Size(min = 3, max = 50) + private String username; + + @NotNull + @Size(min = 3, max = 100) + private String password; +} diff --git a/src/main/resources/templates/login/dto/TokenDto.java b/src/main/resources/templates/login/dto/TokenDto.java new file mode 100644 index 0000000..52b2fbb --- /dev/null +++ b/src/main/resources/templates/login/dto/TokenDto.java @@ -0,0 +1,13 @@ +package templates.login.dto; + +import lombok.*; + +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class TokenDto { + + private String token; +} diff --git a/src/main/resources/templates/login/dto/UserDto.java b/src/main/resources/templates/login/dto/UserDto.java new file mode 100644 index 0000000..bae055f --- /dev/null +++ b/src/main/resources/templates/login/dto/UserDto.java @@ -0,0 +1,45 @@ +package templates.login.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.hotnerds.badgeroad.user.entity.User; +import lombok.*; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Set; +import java.util.stream.Collectors; + +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class UserDto { + + @NotNull + @Size(min = 3, max = 50) + private String username; + + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) + @NotNull + @Size(min = 3, max = 100) + private String password; + + @NotNull + @Size(min = 3, max = 50) + private String nickname; + + private Set authorityDtoSet; + + public static UserDto from(User user) { + if(user == null) return null; + + return UserDto.builder() + .username(user.getUsername()) + .nickname(user.getNickname()) + .authorityDtoSet(user.getAuthorities().stream() + .map(authority -> AuthorityDto.builder().authorityName(authority.getAuthorityName()).build()) + .collect(Collectors.toSet())) + .build(); + } +} \ No newline at end of file diff --git a/src/main/resources/templates/login/entity/Authority.java b/src/main/resources/templates/login/entity/Authority.java new file mode 100644 index 0000000..2d6de54 --- /dev/null +++ b/src/main/resources/templates/login/entity/Authority.java @@ -0,0 +1,22 @@ +package templates.login.entity; + +import lombok.*; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name = "authority") +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class Authority { + + @Id + @Column(name = "authority_name", length = 50) + private String authorityName; +} diff --git a/src/main/resources/templates/login/entity/User.java b/src/main/resources/templates/login/entity/User.java new file mode 100644 index 0000000..fcc41ba --- /dev/null +++ b/src/main/resources/templates/login/entity/User.java @@ -0,0 +1,40 @@ +package templates.login.entity; + +import lombok.*; + +import javax.persistence.*; +import java.util.Set; + +@Entity +@Table(name = "`user`") +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class User { + + @Id + @Column(name = "user_id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long userId; + + @Column(name = "username", length = 50, unique = true) + private String username; + + @Column(name = "password", length = 100) + private String password; + + @Column(name = "nickname", length = 50) + private String nickname; + + @Column(name = "activated") + private boolean activated; + + @ManyToMany + @JoinTable( + name = "user_authority", + joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "user_id")}, + inverseJoinColumns = {@JoinColumn(name = "authority_name", referencedColumnName = "authority_name")}) + private Set authorities; +} diff --git a/src/main/resources/templates/login/exception/DuplicateMemberException.java b/src/main/resources/templates/login/exception/DuplicateMemberException.java new file mode 100644 index 0000000..8d4c35b --- /dev/null +++ b/src/main/resources/templates/login/exception/DuplicateMemberException.java @@ -0,0 +1,16 @@ +package templates.login.exception; + +public class DuplicateMemberException extends RuntimeException { + public DuplicateMemberException() { + super(); + } + public DuplicateMemberException(String message, Throwable cause) { + super(message, cause); + } + public DuplicateMemberException(String message) { + super(message); + } + public DuplicateMemberException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/resources/templates/login/exception/NotFoundMemberException.java b/src/main/resources/templates/login/exception/NotFoundMemberException.java new file mode 100644 index 0000000..2e31504 --- /dev/null +++ b/src/main/resources/templates/login/exception/NotFoundMemberException.java @@ -0,0 +1,16 @@ +package templates.login.exception; + +public class NotFoundMemberException extends RuntimeException { + public NotFoundMemberException() { + super(); + } + public NotFoundMemberException(String message, Throwable cause) { + super(message, cause); + } + public NotFoundMemberException(String message) { + super(message); + } + public NotFoundMemberException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/resources/templates/login/handler/MethodArgumentNotValidExceptionHandler.java b/src/main/resources/templates/login/handler/MethodArgumentNotValidExceptionHandler.java new file mode 100644 index 0000000..3300418 --- /dev/null +++ b/src/main/resources/templates/login/handler/MethodArgumentNotValidExceptionHandler.java @@ -0,0 +1,37 @@ +package templates.login.handler; + +import com.hotnerds.badgeroad.user.dto.ErrorDto; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; + +import java.util.List; + +import static org.springframework.http.HttpStatus.BAD_REQUEST; + +@Order(Ordered.HIGHEST_PRECEDENCE) +@ControllerAdvice +public class MethodArgumentNotValidExceptionHandler { + + @ResponseStatus(BAD_REQUEST) + @ResponseBody + @ExceptionHandler(MethodArgumentNotValidException.class) + public ErrorDto methodArgumentNotValidException(MethodArgumentNotValidException ex) { + BindingResult result = ex.getBindingResult(); + List fieldErrors = result.getFieldErrors(); + return processFieldErrors(fieldErrors); + } + + private ErrorDto processFieldErrors(List fieldErrors) { + ErrorDto errorDTO = new ErrorDto(BAD_REQUEST.value(), "@Valid Error"); + for (org.springframework.validation.FieldError fieldError: fieldErrors) { + errorDTO.addFieldError(fieldError.getObjectName(), fieldError.getField(), fieldError.getDefaultMessage()); + } + return errorDTO; + } +} \ No newline at end of file diff --git a/src/main/resources/templates/login/handler/RestResponseExceptionHandler.java b/src/main/resources/templates/login/handler/RestResponseExceptionHandler.java new file mode 100644 index 0000000..eff3038 --- /dev/null +++ b/src/main/resources/templates/login/handler/RestResponseExceptionHandler.java @@ -0,0 +1,33 @@ +package templates.login.handler; + +import com.hotnerds.badgeroad.user.dto.ErrorDto; +import com.hotnerds.badgeroad.user.exception.DuplicateMemberException; +import com.hotnerds.badgeroad.user.exception.NotFoundMemberException; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.context.request.WebRequest; +import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; + +import static org.springframework.http.HttpStatus.CONFLICT; +import static org.springframework.http.HttpStatus.FORBIDDEN; + +@ControllerAdvice +public class RestResponseExceptionHandler extends ResponseEntityExceptionHandler { + + @ResponseStatus(CONFLICT) + @ExceptionHandler(value = { DuplicateMemberException.class }) + @ResponseBody + protected ErrorDto badRequest(RuntimeException ex, WebRequest request) { + return new ErrorDto(CONFLICT.value(), ex.getMessage()); + } + + @ResponseStatus(FORBIDDEN) + @ExceptionHandler(value = { NotFoundMemberException.class, AccessDeniedException.class }) + @ResponseBody + protected ErrorDto forbidden(RuntimeException ex, WebRequest request) { + return new ErrorDto(FORBIDDEN.value(), ex.getMessage()); + } +} \ No newline at end of file diff --git a/src/main/resources/templates/login/jwt/JwtAccessDeniedHandler.java b/src/main/resources/templates/login/jwt/JwtAccessDeniedHandler.java new file mode 100644 index 0000000..511d48e --- /dev/null +++ b/src/main/resources/templates/login/jwt/JwtAccessDeniedHandler.java @@ -0,0 +1,18 @@ +package templates.login.jwt; + +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.web.access.AccessDeniedHandler; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +@Component +public class JwtAccessDeniedHandler implements AccessDeniedHandler { + @Override + public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException { + //필요한 권한이 없이 접근하려 할때 403 + response.sendError(HttpServletResponse.SC_FORBIDDEN); + } +} diff --git a/src/main/resources/templates/login/jwt/JwtAuthenticationEntryPoint.java b/src/main/resources/templates/login/jwt/JwtAuthenticationEntryPoint.java new file mode 100644 index 0000000..b68a60f --- /dev/null +++ b/src/main/resources/templates/login/jwt/JwtAuthenticationEntryPoint.java @@ -0,0 +1,20 @@ +package templates.login.jwt; + +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +@Component +public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { + @Override + public void commence(HttpServletRequest request, + HttpServletResponse response, + AuthenticationException authException) throws IOException { + // 유효한 자격증명을 제공하지 않고 접근하려 할때 401 + response.sendError(HttpServletResponse.SC_UNAUTHORIZED); + } +} diff --git a/src/main/resources/templates/login/jwt/JwtFilter.java b/src/main/resources/templates/login/jwt/JwtFilter.java new file mode 100644 index 0000000..0e176ad --- /dev/null +++ b/src/main/resources/templates/login/jwt/JwtFilter.java @@ -0,0 +1,52 @@ +package templates.login.jwt; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.util.StringUtils; +import org.springframework.web.filter.GenericFilterBean; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; + +public class JwtFilter extends GenericFilterBean { + + private static final Logger logger = LoggerFactory.getLogger(JwtFilter.class); + public static final String AUTHORIZATION_HEADER = "Authorization"; + private TokenProvider tokenProvider; + public JwtFilter(TokenProvider tokenProvider) { + this.tokenProvider = tokenProvider; + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { + HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest; + String jwt = resolveToken(httpServletRequest); + String requestURI = httpServletRequest.getRequestURI(); + + if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) { + Authentication authentication = tokenProvider.getAuthentication(jwt); + SecurityContextHolder.getContext().setAuthentication(authentication); + logger.debug("Security Context에 '{}' 인증 정보를 저장했습니다, uri: {}", authentication.getName(), requestURI); + } else { + logger.debug("유효한 JWT 토큰이 없습니다, uri: {}", requestURI); + } + + filterChain.doFilter(servletRequest, servletResponse); + } + + private String resolveToken(HttpServletRequest request) { + String bearerToken = request.getHeader(AUTHORIZATION_HEADER); + + if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { + return bearerToken.substring(7); + } + + return null; + } +} diff --git a/src/main/resources/templates/login/jwt/JwtSecurityConfig.java b/src/main/resources/templates/login/jwt/JwtSecurityConfig.java new file mode 100644 index 0000000..c3782c8 --- /dev/null +++ b/src/main/resources/templates/login/jwt/JwtSecurityConfig.java @@ -0,0 +1,21 @@ +package templates.login.jwt; + +import org.springframework.security.config.annotation.SecurityConfigurerAdapter; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.web.DefaultSecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +public class JwtSecurityConfig extends SecurityConfigurerAdapter { + private TokenProvider tokenProvider; + public JwtSecurityConfig(TokenProvider tokenProvider) { + this.tokenProvider = tokenProvider; + } + + @Override + public void configure(HttpSecurity http) { + http.addFilterBefore( + new JwtFilter(tokenProvider), + UsernamePasswordAuthenticationFilter.class + ); + } +} diff --git a/src/main/resources/templates/login/jwt/TokenProvider.java b/src/main/resources/templates/login/jwt/TokenProvider.java new file mode 100644 index 0000000..71775a6 --- /dev/null +++ b/src/main/resources/templates/login/jwt/TokenProvider.java @@ -0,0 +1,94 @@ +package templates.login.jwt; + +import io.jsonwebtoken.*; +import io.jsonwebtoken.io.Decoders; +import io.jsonwebtoken.security.Keys; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.User; +import org.springframework.stereotype.Component; + +import java.security.Key; +import java.util.Arrays; +import java.util.Collection; +import java.util.Date; +import java.util.stream.Collectors; + +@Component +public class TokenProvider implements InitializingBean { + + private final Logger logger = LoggerFactory.getLogger(TokenProvider.class); + private static final String AUTHORITIES_KEY = "auth"; + private final String secret; + private final long tokenValidityInMilliseconds; + private Key key; + + public TokenProvider( + @Value("${jwt.secret}") String secret, + @Value("${jwt.token-validity-in-seconds}") long tokenValidityInSeconds) { + this.secret = secret; + this.tokenValidityInMilliseconds = tokenValidityInSeconds * 1000; + } + + @Override + public void afterPropertiesSet() { + byte[] keyBytes = Decoders.BASE64.decode(secret); + this.key = Keys.hmacShaKeyFor(keyBytes); + } + + public String createToken(Authentication authentication) { + String authorities = authentication.getAuthorities().stream() + .map(GrantedAuthority::getAuthority) + .collect(Collectors.joining(",")); + + long now = (new Date()).getTime(); + Date validity = new Date(now + this.tokenValidityInMilliseconds); + + return Jwts.builder() + .setSubject(authentication.getName()) + .claim(AUTHORITIES_KEY, authorities) + .signWith(key, SignatureAlgorithm.HS512) + .setExpiration(validity) + .compact(); + } + + public Authentication getAuthentication(String token) { + Claims claims = Jwts + .parserBuilder() + .setSigningKey(key) + .build() + .parseClaimsJws(token) + .getBody(); + + Collection authorities = + Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(",")) + .map(SimpleGrantedAuthority::new) + .collect(Collectors.toList()); + + User principal = new User(claims.getSubject(), "", authorities); + + return new UsernamePasswordAuthenticationToken(principal, token, authorities); + } + + public boolean validateToken(String token) { + try { + Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token); + return true; + } catch (io.jsonwebtoken.security.SecurityException | MalformedJwtException e) { + logger.info("잘못된 JWT 서명입니다."); + } catch (ExpiredJwtException e) { + logger.info("만료된 JWT 토큰입니다."); + } catch (UnsupportedJwtException e) { + logger.info("지원되지 않는 JWT 토큰입니다."); + } catch (IllegalArgumentException e) { + logger.info("JWT 토큰이 잘못되었습니다."); + } + return false; + } +} diff --git a/src/main/resources/templates/login/repository/AuthorityRepository.java b/src/main/resources/templates/login/repository/AuthorityRepository.java new file mode 100644 index 0000000..e5dc88f --- /dev/null +++ b/src/main/resources/templates/login/repository/AuthorityRepository.java @@ -0,0 +1,7 @@ +package templates.login.repository; + +import com.hotnerds.badgeroad.user.entity.Authority; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface AuthorityRepository extends JpaRepository { +} diff --git a/src/main/resources/templates/login/repository/UserRepository.java b/src/main/resources/templates/login/repository/UserRepository.java new file mode 100644 index 0000000..9df8a77 --- /dev/null +++ b/src/main/resources/templates/login/repository/UserRepository.java @@ -0,0 +1,12 @@ +package templates.login.repository; + +import com.hotnerds.badgeroad.user.entity.User; +import org.springframework.data.jpa.repository.EntityGraph; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface UserRepository extends JpaRepository { + @EntityGraph(attributePaths = "authorities") + Optional findOneWithAuthoritiesByUsername(String username); +} diff --git a/src/main/resources/templates/login/service/CustomUserDetailsService.java b/src/main/resources/templates/login/service/CustomUserDetailsService.java new file mode 100644 index 0000000..ced7126 --- /dev/null +++ b/src/main/resources/templates/login/service/CustomUserDetailsService.java @@ -0,0 +1,45 @@ +package templates.login.service; + +import com.hotnerds.badgeroad.user.entity.User; +import com.hotnerds.badgeroad.user.repository.UserRepository; +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.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.stream.Collectors; + +@Component("userDetailsService") +public class CustomUserDetailsService implements UserDetailsService { + private final UserRepository userRepository; + + public CustomUserDetailsService(UserRepository userRepository) { + this.userRepository = userRepository; + } + + @Override + @Transactional + public UserDetails loadUserByUsername(final String username) { + return userRepository.findOneWithAuthoritiesByUsername(username) + .map(user -> createUser(username, user)) + .orElseThrow(() -> new UsernameNotFoundException(username + " -> 데이터베이스에서 찾을 수 없습니다.")); + } + + private org.springframework.security.core.userdetails.User createUser(String username, User user) { + if (!user.isActivated()) { + throw new RuntimeException(username + " -> 활성화되어 있지 않습니다."); + } + + List grantedAuthorities = user.getAuthorities().stream() + .map(authority -> new SimpleGrantedAuthority(authority.getAuthorityName())) + .collect(Collectors.toList()); + + return new org.springframework.security.core.userdetails.User(user.getUsername(), + user.getPassword(), + grantedAuthorities); + } +} diff --git a/src/main/resources/templates/login/service/UserService.java b/src/main/resources/templates/login/service/UserService.java new file mode 100644 index 0000000..3912b04 --- /dev/null +++ b/src/main/resources/templates/login/service/UserService.java @@ -0,0 +1,60 @@ +package templates.login.service; + +import com.hotnerds.badgeroad.user.dto.UserDto; +import com.hotnerds.badgeroad.user.entity.Authority; +import com.hotnerds.badgeroad.user.entity.User; +import com.hotnerds.badgeroad.user.exception.DuplicateMemberException; +import com.hotnerds.badgeroad.user.exception.NotFoundMemberException; +import com.hotnerds.badgeroad.user.repository.UserRepository; +import com.hotnerds.badgeroad.user.util.SecurityUtil; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collections; + +@Service +public class UserService { + private final UserRepository userRepository; + private final PasswordEncoder passwordEncoder; + + public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) { + this.userRepository = userRepository; + this.passwordEncoder = passwordEncoder; + } + + @Transactional + public UserDto signup(UserDto userDto) { + if (userRepository.findOneWithAuthoritiesByUsername(userDto.getUsername()).orElse(null) != null) { + throw new DuplicateMemberException("이미 가입되어 있는 유저입니다."); + } + + Authority authority = Authority.builder() + .authorityName("ROLE_USER") + .build(); + + User user = User.builder() + .username(userDto.getUsername()) + .password(passwordEncoder.encode(userDto.getPassword())) + .nickname(userDto.getNickname()) + .authorities(Collections.singleton(authority)) + .activated(true) + .build(); + + return UserDto.from(userRepository.save(user)); + } + + @Transactional(readOnly = true) + public UserDto getUserWithAuthorities(String username) { + return UserDto.from(userRepository.findOneWithAuthoritiesByUsername(username).orElse(null)); + } + + @Transactional(readOnly = true) + public UserDto getMyUserWithAuthorities() { + return UserDto.from( + SecurityUtil.getCurrentUsername() + .flatMap(userRepository::findOneWithAuthoritiesByUsername) + .orElseThrow(() -> new NotFoundMemberException("Member not found")) + ); + } +} diff --git a/src/main/resources/templates/login/util/SecurityUtil.java b/src/main/resources/templates/login/util/SecurityUtil.java new file mode 100644 index 0000000..40999b6 --- /dev/null +++ b/src/main/resources/templates/login/util/SecurityUtil.java @@ -0,0 +1,35 @@ +package templates.login.util; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; + +import java.util.Optional; + +public class SecurityUtil { + + private static final Logger logger = LoggerFactory.getLogger(SecurityUtil.class); + + private SecurityUtil() {} + + public static Optional getCurrentUsername() { + final Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + + if (authentication == null) { + logger.debug("Security Context에 인증 정보가 없습니다."); + return Optional.empty(); + } + + String username = null; + if (authentication.getPrincipal() instanceof UserDetails) { + UserDetails springSecurityUser = (UserDetails) authentication.getPrincipal(); + username = springSecurityUser.getUsername(); + } else if (authentication.getPrincipal() instanceof String) { + username = (String) authentication.getPrincipal(); + } + + return Optional.ofNullable(username); + } +} diff --git a/src/main/resources/templates/main.html b/src/main/resources/templates/main.html new file mode 100644 index 0000000..d3790b1 --- /dev/null +++ b/src/main/resources/templates/main.html @@ -0,0 +1,13 @@ + + + + + + +

+

HOME

+

LOGIN

+

SIGNUP

+ + + \ No newline at end of file From df4b37a770f6c2205c88eac31aea1f2981ab91e9 Mon Sep 17 00:00:00 2001 From: shinjbin Date: Wed, 14 Dec 2022 23:50:40 +0900 Subject: [PATCH 02/11] init --- .../badgeroad/home/HomeController.java | 13 + .../badgeroad/home/LoginSignupController.java | 20 ++ .../badgeroad/login/config/CorsConfig.java | 23 ++ .../login/config/SecurityConfig.java | 89 +++++++ .../login/controller/AuthController.java | 48 ++++ .../login/controller/UserController.java | 56 ++++ .../badgeroad/login/dto/AuthorityDto.java | 12 + .../badgeroad/login/dto/ErrorDto.java | 34 +++ .../badgeroad/login/dto/LoginDto.java | 22 ++ .../badgeroad/login/dto/TokenDto.java | 13 + .../hotnerds/badgeroad/login/dto/UserDto.java | 45 ++++ .../badgeroad/login/entity/Authority.java | 22 ++ .../hotnerds/badgeroad/login/entity/User.java | 40 +++ .../exception/DuplicateMemberException.java | 16 ++ .../exception/NotFoundMemberException.java | 16 ++ ...ethodArgumentNotValidExceptionHandler.java | 37 +++ .../handler/RestResponseExceptionHandler.java | 33 +++ .../login/jwt/JwtAccessDeniedHandler.java | 18 ++ .../jwt/JwtAuthenticationEntryPoint.java | 20 ++ .../badgeroad/login/jwt/JwtFilter.java | 52 ++++ .../login/jwt/JwtSecurityConfig.java | 21 ++ .../badgeroad/login/jwt/TokenProvider.java | 94 +++++++ .../login/repository/AuthorityRepository.java | 7 + .../login/repository/UserRepository.java | 12 + .../service/CustomUserDetailsService.java | 45 ++++ .../badgeroad/login/service/UserService.java | 60 +++++ .../badgeroad/login/util/SecurityUtil.java | 35 +++ .../badgeroad/openapi/NaverClient.java | 243 ++++++++++++++++++ .../badgeroad/openapi/OpenApiController.java | 41 +++ .../badgeroad/openapi/dto/SearchImageReq.java | 35 +++ .../badgeroad/openapi/dto/SearchImageRes.java | 28 ++ .../badgeroad/openapi/dto/SearchLocalReq.java | 32 +++ .../badgeroad/openapi/dto/SearchLocalRes.java | 36 +++ src/main/resources/data.sql | 9 + 34 files changed, 1327 insertions(+) create mode 100644 src/main/java/com/hotnerds/badgeroad/home/HomeController.java create mode 100644 src/main/java/com/hotnerds/badgeroad/home/LoginSignupController.java create mode 100644 src/main/java/com/hotnerds/badgeroad/login/config/CorsConfig.java create mode 100644 src/main/java/com/hotnerds/badgeroad/login/config/SecurityConfig.java create mode 100644 src/main/java/com/hotnerds/badgeroad/login/controller/AuthController.java create mode 100644 src/main/java/com/hotnerds/badgeroad/login/controller/UserController.java create mode 100644 src/main/java/com/hotnerds/badgeroad/login/dto/AuthorityDto.java create mode 100644 src/main/java/com/hotnerds/badgeroad/login/dto/ErrorDto.java create mode 100644 src/main/java/com/hotnerds/badgeroad/login/dto/LoginDto.java create mode 100644 src/main/java/com/hotnerds/badgeroad/login/dto/TokenDto.java create mode 100644 src/main/java/com/hotnerds/badgeroad/login/dto/UserDto.java create mode 100644 src/main/java/com/hotnerds/badgeroad/login/entity/Authority.java create mode 100644 src/main/java/com/hotnerds/badgeroad/login/entity/User.java create mode 100644 src/main/java/com/hotnerds/badgeroad/login/exception/DuplicateMemberException.java create mode 100644 src/main/java/com/hotnerds/badgeroad/login/exception/NotFoundMemberException.java create mode 100644 src/main/java/com/hotnerds/badgeroad/login/handler/MethodArgumentNotValidExceptionHandler.java create mode 100644 src/main/java/com/hotnerds/badgeroad/login/handler/RestResponseExceptionHandler.java create mode 100644 src/main/java/com/hotnerds/badgeroad/login/jwt/JwtAccessDeniedHandler.java create mode 100644 src/main/java/com/hotnerds/badgeroad/login/jwt/JwtAuthenticationEntryPoint.java create mode 100644 src/main/java/com/hotnerds/badgeroad/login/jwt/JwtFilter.java create mode 100644 src/main/java/com/hotnerds/badgeroad/login/jwt/JwtSecurityConfig.java create mode 100644 src/main/java/com/hotnerds/badgeroad/login/jwt/TokenProvider.java create mode 100644 src/main/java/com/hotnerds/badgeroad/login/repository/AuthorityRepository.java create mode 100644 src/main/java/com/hotnerds/badgeroad/login/repository/UserRepository.java create mode 100644 src/main/java/com/hotnerds/badgeroad/login/service/CustomUserDetailsService.java create mode 100644 src/main/java/com/hotnerds/badgeroad/login/service/UserService.java create mode 100644 src/main/java/com/hotnerds/badgeroad/login/util/SecurityUtil.java create mode 100644 src/main/java/com/hotnerds/badgeroad/openapi/NaverClient.java create mode 100644 src/main/java/com/hotnerds/badgeroad/openapi/OpenApiController.java create mode 100644 src/main/java/com/hotnerds/badgeroad/openapi/dto/SearchImageReq.java create mode 100644 src/main/java/com/hotnerds/badgeroad/openapi/dto/SearchImageRes.java create mode 100644 src/main/java/com/hotnerds/badgeroad/openapi/dto/SearchLocalReq.java create mode 100644 src/main/java/com/hotnerds/badgeroad/openapi/dto/SearchLocalRes.java create mode 100644 src/main/resources/data.sql diff --git a/src/main/java/com/hotnerds/badgeroad/home/HomeController.java b/src/main/java/com/hotnerds/badgeroad/home/HomeController.java new file mode 100644 index 0000000..119eb29 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/home/HomeController.java @@ -0,0 +1,13 @@ +package com.hotnerds.badgeroad.home; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +@Controller +public class HomeController { + + @GetMapping("index") + public String homepage() { + return "index"; + } +} diff --git a/src/main/java/com/hotnerds/badgeroad/home/LoginSignupController.java b/src/main/java/com/hotnerds/badgeroad/home/LoginSignupController.java new file mode 100644 index 0000000..14ec00f --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/home/LoginSignupController.java @@ -0,0 +1,20 @@ +package com.hotnerds.badgeroad.home; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +@RequestMapping("/user") +public class LoginSignupController { + + @GetMapping("/login") + public String login() { + return "login"; + } + + @GetMapping("/signup") + public String signup() { + return "signup"; + } +} diff --git a/src/main/java/com/hotnerds/badgeroad/login/config/CorsConfig.java b/src/main/java/com/hotnerds/badgeroad/login/config/CorsConfig.java new file mode 100644 index 0000000..c1cf3a6 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/login/config/CorsConfig.java @@ -0,0 +1,23 @@ +package com.hotnerds.badgeroad.login.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; + +@Configuration +public class CorsConfig { + @Bean + public CorsFilter corsFilter() { + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + CorsConfiguration config = new CorsConfiguration(); + config.setAllowCredentials(true); + config.addAllowedOrigin("*"); + config.addAllowedHeader("*"); + config.addAllowedMethod("*"); + + source.registerCorsConfiguration("/api/**", config); + return new CorsFilter(source); + } +} diff --git a/src/main/java/com/hotnerds/badgeroad/login/config/SecurityConfig.java b/src/main/java/com/hotnerds/badgeroad/login/config/SecurityConfig.java new file mode 100644 index 0000000..0da8d89 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/login/config/SecurityConfig.java @@ -0,0 +1,89 @@ +package com.hotnerds.badgeroad.login.config; + +import com.hotnerds.badgeroad.login.jwt.JwtAccessDeniedHandler; +import com.hotnerds.badgeroad.login.jwt.JwtAuthenticationEntryPoint; +import com.hotnerds.badgeroad.login.jwt.JwtSecurityConfig; +import com.hotnerds.badgeroad.login.jwt.TokenProvider; +import org.springframework.context.annotation.Bean; +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; +import org.springframework.web.filter.CorsFilter; + +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true) +public class SecurityConfig { + private final TokenProvider tokenProvider; + private final CorsFilter corsFilter; + private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; + private final JwtAccessDeniedHandler jwtAccessDeniedHandler; + + public SecurityConfig( + TokenProvider tokenProvider, + CorsFilter corsFilter, + JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint, + JwtAccessDeniedHandler jwtAccessDeniedHandler + ) { + this.tokenProvider = tokenProvider; + this.corsFilter = corsFilter; + this.jwtAuthenticationEntryPoint = jwtAuthenticationEntryPoint; + this.jwtAccessDeniedHandler = jwtAccessDeniedHandler; + } + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Bean + public WebSecurityCustomizer webSecurityCustomizer() { + return (web) -> web.ignoring().antMatchers("/h2-console/**" + , "/favicon.ico" + , "/error"); + } + + @Bean + public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { + httpSecurity + // token을 사용하는 방식이기 때문에 csrf를 disable합니다. + .csrf().disable() + + .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class) + + .exceptionHandling() + .authenticationEntryPoint(jwtAuthenticationEntryPoint) + .accessDeniedHandler(jwtAccessDeniedHandler) + + // enable h2-console + .and() + .headers() + .frameOptions() + .sameOrigin() + + // 세션을 사용하지 않기 때문에 STATELESS로 설정 + .and() + .sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.STATELESS) + + .and() + .authorizeRequests() + .antMatchers("/").permitAll() + .antMatchers("/user/**").permitAll() + .antMatchers("/api/hello").permitAll() + .antMatchers("/api/authenticate").permitAll() + .antMatchers("/api/signup").permitAll() + + .anyRequest().authenticated() + + .and() + .apply(new JwtSecurityConfig(tokenProvider)); + + return httpSecurity.build(); + } +} \ No newline at end of file diff --git a/src/main/java/com/hotnerds/badgeroad/login/controller/AuthController.java b/src/main/java/com/hotnerds/badgeroad/login/controller/AuthController.java new file mode 100644 index 0000000..1516278 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/login/controller/AuthController.java @@ -0,0 +1,48 @@ +package com.hotnerds.badgeroad.login.controller; + +import com.hotnerds.badgeroad.login.dto.LoginDto; +import com.hotnerds.badgeroad.login.dto.TokenDto; +import com.hotnerds.badgeroad.login.jwt.JwtFilter; +import com.hotnerds.badgeroad.login.jwt.TokenProvider; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +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 javax.validation.Valid; + +@RestController +@RequestMapping("/api") +public class AuthController { + private final TokenProvider tokenProvider; + private final AuthenticationManagerBuilder authenticationManagerBuilder; + + public AuthController(TokenProvider tokenProvider, AuthenticationManagerBuilder authenticationManagerBuilder) { + this.tokenProvider = tokenProvider; + this.authenticationManagerBuilder = authenticationManagerBuilder; + } + + @PostMapping("/authenticate") + public ResponseEntity authorize(@Valid @RequestBody LoginDto loginDto) { + + UsernamePasswordAuthenticationToken authenticationToken = + new UsernamePasswordAuthenticationToken(loginDto.getUsername(), loginDto.getPassword()); + + Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken); + SecurityContextHolder.getContext().setAuthentication(authentication); + + String jwt = tokenProvider.createToken(authentication); + + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.add(JwtFilter.AUTHORIZATION_HEADER, "Bearer " + jwt); + + return new ResponseEntity<>(new TokenDto(jwt), httpHeaders, HttpStatus.OK); + } +} diff --git a/src/main/java/com/hotnerds/badgeroad/login/controller/UserController.java b/src/main/java/com/hotnerds/badgeroad/login/controller/UserController.java new file mode 100644 index 0000000..3c3f5d6 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/login/controller/UserController.java @@ -0,0 +1,56 @@ +package com.hotnerds.badgeroad.login.controller; + +import com.hotnerds.badgeroad.login.dto.UserDto; +import com.hotnerds.badgeroad.login.service.UserService; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; + +@RestController +@RequestMapping("/api") +public class UserController { + private final UserService userService; + + public UserController(UserService userService) { + this.userService = userService; + } + + @GetMapping("/") + public String index() { + return "index"; + } + + @GetMapping("/hello") + public ResponseEntity hello() { + return ResponseEntity.ok("hello"); + } + + @PostMapping("/test-redirect") + public void testRedirect(HttpServletResponse response) throws IOException { + response.sendRedirect("/api/user"); + } + + @PostMapping("/signup") + public ResponseEntity signup( + @Valid @RequestBody UserDto userDto + ) { + return ResponseEntity.ok(userService.signup(userDto)); + } + + @GetMapping("/user") + @PreAuthorize("hasAnyRole('USER','ADMIN')") + public ResponseEntity getMyUserInfo(HttpServletRequest request) { + return ResponseEntity.ok(userService.getMyUserWithAuthorities()); + } + + @GetMapping("/user/{username}") + @PreAuthorize("hasAnyRole('ADMIN')") + public ResponseEntity getUserInfo(@PathVariable String username) { + return ResponseEntity.ok(userService.getUserWithAuthorities(username)); + } +} diff --git a/src/main/java/com/hotnerds/badgeroad/login/dto/AuthorityDto.java b/src/main/java/com/hotnerds/badgeroad/login/dto/AuthorityDto.java new file mode 100644 index 0000000..a809175 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/login/dto/AuthorityDto.java @@ -0,0 +1,12 @@ +package com.hotnerds.badgeroad.login.dto; + +import lombok.*; + +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class AuthorityDto { + private String authorityName; +} \ No newline at end of file diff --git a/src/main/java/com/hotnerds/badgeroad/login/dto/ErrorDto.java b/src/main/java/com/hotnerds/badgeroad/login/dto/ErrorDto.java new file mode 100644 index 0000000..82b6e17 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/login/dto/ErrorDto.java @@ -0,0 +1,34 @@ +package com.hotnerds.badgeroad.login.dto; + +import org.springframework.validation.FieldError; + +import java.util.ArrayList; +import java.util.List; + +public class ErrorDto { + private final int status; + private final String message; + private List fieldErrors = new ArrayList<>(); + + public ErrorDto(int status, String message) { + this.status = status; + this.message = message; + } + + public int getStatus() { + return status; + } + + public String getMessage() { + return message; + } + + public void addFieldError(String objectName, String path, String message) { + FieldError error = new FieldError(objectName, path, message); + fieldErrors.add(error); + } + + public List getFieldErrors() { + return fieldErrors; + } +} diff --git a/src/main/java/com/hotnerds/badgeroad/login/dto/LoginDto.java b/src/main/java/com/hotnerds/badgeroad/login/dto/LoginDto.java new file mode 100644 index 0000000..97b452e --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/login/dto/LoginDto.java @@ -0,0 +1,22 @@ +package com.hotnerds.badgeroad.login.dto; + +import lombok.*; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class LoginDto { + + @NotNull + @Size(min = 3, max = 50) + private String username; + + @NotNull + @Size(min = 3, max = 100) + private String password; +} diff --git a/src/main/java/com/hotnerds/badgeroad/login/dto/TokenDto.java b/src/main/java/com/hotnerds/badgeroad/login/dto/TokenDto.java new file mode 100644 index 0000000..d7ad345 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/login/dto/TokenDto.java @@ -0,0 +1,13 @@ +package com.hotnerds.badgeroad.login.dto; + +import lombok.*; + +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class TokenDto { + + private String token; +} diff --git a/src/main/java/com/hotnerds/badgeroad/login/dto/UserDto.java b/src/main/java/com/hotnerds/badgeroad/login/dto/UserDto.java new file mode 100644 index 0000000..66639e5 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/login/dto/UserDto.java @@ -0,0 +1,45 @@ +package com.hotnerds.badgeroad.login.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.hotnerds.badgeroad.login.entity.User; +import lombok.*; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Set; +import java.util.stream.Collectors; + +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class UserDto { + + @NotNull + @Size(min = 3, max = 50) + private String username; + + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) + @NotNull + @Size(min = 3, max = 100) + private String password; + + @NotNull + @Size(min = 3, max = 50) + private String nickname; + + private Set authorityDtoSet; + + public static UserDto from(User user) { + if(user == null) return null; + + return UserDto.builder() + .username(user.getUsername()) + .nickname(user.getNickname()) + .authorityDtoSet(user.getAuthorities().stream() + .map(authority -> AuthorityDto.builder().authorityName(authority.getAuthorityName()).build()) + .collect(Collectors.toSet())) + .build(); + } +} \ No newline at end of file diff --git a/src/main/java/com/hotnerds/badgeroad/login/entity/Authority.java b/src/main/java/com/hotnerds/badgeroad/login/entity/Authority.java new file mode 100644 index 0000000..d84e941 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/login/entity/Authority.java @@ -0,0 +1,22 @@ +package com.hotnerds.badgeroad.login.entity; + +import lombok.*; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name = "authority") +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class Authority { + + @Id + @Column(name = "authority_name", length = 50) + private String authorityName; +} diff --git a/src/main/java/com/hotnerds/badgeroad/login/entity/User.java b/src/main/java/com/hotnerds/badgeroad/login/entity/User.java new file mode 100644 index 0000000..783a15a --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/login/entity/User.java @@ -0,0 +1,40 @@ +package com.hotnerds.badgeroad.login.entity; + +import lombok.*; + +import javax.persistence.*; +import java.util.Set; + +@Entity +@Table(name = "`user`") +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class User { + + @Id + @Column(name = "user_id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long userId; + + @Column(name = "username", length = 50, unique = true) + private String username; + + @Column(name = "password", length = 100) + private String password; + + @Column(name = "nickname", length = 50) + private String nickname; + + @Column(name = "activated") + private boolean activated; + + @ManyToMany + @JoinTable( + name = "user_authority", + joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "user_id")}, + inverseJoinColumns = {@JoinColumn(name = "authority_name", referencedColumnName = "authority_name")}) + private Set authorities; +} diff --git a/src/main/java/com/hotnerds/badgeroad/login/exception/DuplicateMemberException.java b/src/main/java/com/hotnerds/badgeroad/login/exception/DuplicateMemberException.java new file mode 100644 index 0000000..0d6e9c9 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/login/exception/DuplicateMemberException.java @@ -0,0 +1,16 @@ +package com.hotnerds.badgeroad.login.exception; + +public class DuplicateMemberException extends RuntimeException { + public DuplicateMemberException() { + super(); + } + public DuplicateMemberException(String message, Throwable cause) { + super(message, cause); + } + public DuplicateMemberException(String message) { + super(message); + } + public DuplicateMemberException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/com/hotnerds/badgeroad/login/exception/NotFoundMemberException.java b/src/main/java/com/hotnerds/badgeroad/login/exception/NotFoundMemberException.java new file mode 100644 index 0000000..9129846 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/login/exception/NotFoundMemberException.java @@ -0,0 +1,16 @@ +package com.hotnerds.badgeroad.login.exception; + +public class NotFoundMemberException extends RuntimeException { + public NotFoundMemberException() { + super(); + } + public NotFoundMemberException(String message, Throwable cause) { + super(message, cause); + } + public NotFoundMemberException(String message) { + super(message); + } + public NotFoundMemberException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/com/hotnerds/badgeroad/login/handler/MethodArgumentNotValidExceptionHandler.java b/src/main/java/com/hotnerds/badgeroad/login/handler/MethodArgumentNotValidExceptionHandler.java new file mode 100644 index 0000000..3404716 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/login/handler/MethodArgumentNotValidExceptionHandler.java @@ -0,0 +1,37 @@ +package com.hotnerds.badgeroad.login.handler; + +import com.hotnerds.badgeroad.login.dto.ErrorDto; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; + +import java.util.List; + +import static org.springframework.http.HttpStatus.BAD_REQUEST; + +@Order(Ordered.HIGHEST_PRECEDENCE) +@ControllerAdvice +public class MethodArgumentNotValidExceptionHandler { + + @ResponseStatus(BAD_REQUEST) + @ResponseBody + @ExceptionHandler(MethodArgumentNotValidException.class) + public ErrorDto methodArgumentNotValidException(MethodArgumentNotValidException ex) { + BindingResult result = ex.getBindingResult(); + List fieldErrors = result.getFieldErrors(); + return processFieldErrors(fieldErrors); + } + + private ErrorDto processFieldErrors(List fieldErrors) { + ErrorDto errorDTO = new ErrorDto(BAD_REQUEST.value(), "@Valid Error"); + for (org.springframework.validation.FieldError fieldError: fieldErrors) { + errorDTO.addFieldError(fieldError.getObjectName(), fieldError.getField(), fieldError.getDefaultMessage()); + } + return errorDTO; + } +} \ No newline at end of file diff --git a/src/main/java/com/hotnerds/badgeroad/login/handler/RestResponseExceptionHandler.java b/src/main/java/com/hotnerds/badgeroad/login/handler/RestResponseExceptionHandler.java new file mode 100644 index 0000000..82885b3 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/login/handler/RestResponseExceptionHandler.java @@ -0,0 +1,33 @@ +package com.hotnerds.badgeroad.login.handler; + +import com.hotnerds.badgeroad.login.dto.ErrorDto; +import com.hotnerds.badgeroad.login.exception.DuplicateMemberException; +import com.hotnerds.badgeroad.login.exception.NotFoundMemberException; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.context.request.WebRequest; +import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; + +import static org.springframework.http.HttpStatus.CONFLICT; +import static org.springframework.http.HttpStatus.FORBIDDEN; + +@ControllerAdvice +public class RestResponseExceptionHandler extends ResponseEntityExceptionHandler { + + @ResponseStatus(CONFLICT) + @ExceptionHandler(value = { DuplicateMemberException.class }) + @ResponseBody + protected ErrorDto badRequest(RuntimeException ex, WebRequest request) { + return new ErrorDto(CONFLICT.value(), ex.getMessage()); + } + + @ResponseStatus(FORBIDDEN) + @ExceptionHandler(value = { NotFoundMemberException.class, AccessDeniedException.class }) + @ResponseBody + protected ErrorDto forbidden(RuntimeException ex, WebRequest request) { + return new ErrorDto(FORBIDDEN.value(), ex.getMessage()); + } +} \ No newline at end of file diff --git a/src/main/java/com/hotnerds/badgeroad/login/jwt/JwtAccessDeniedHandler.java b/src/main/java/com/hotnerds/badgeroad/login/jwt/JwtAccessDeniedHandler.java new file mode 100644 index 0000000..c1cc447 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/login/jwt/JwtAccessDeniedHandler.java @@ -0,0 +1,18 @@ +package com.hotnerds.badgeroad.login.jwt; + +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.web.access.AccessDeniedHandler; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +@Component +public class JwtAccessDeniedHandler implements AccessDeniedHandler { + @Override + public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException { + //필요한 권한이 없이 접근하려 할때 403 + response.sendError(HttpServletResponse.SC_FORBIDDEN); + } +} diff --git a/src/main/java/com/hotnerds/badgeroad/login/jwt/JwtAuthenticationEntryPoint.java b/src/main/java/com/hotnerds/badgeroad/login/jwt/JwtAuthenticationEntryPoint.java new file mode 100644 index 0000000..9fabc64 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/login/jwt/JwtAuthenticationEntryPoint.java @@ -0,0 +1,20 @@ +package com.hotnerds.badgeroad.login.jwt; + +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +@Component +public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { + @Override + public void commence(HttpServletRequest request, + HttpServletResponse response, + AuthenticationException authException) throws IOException { + // 유효한 자격증명을 제공하지 않고 접근하려 할때 401 + response.sendError(HttpServletResponse.SC_UNAUTHORIZED); + } +} diff --git a/src/main/java/com/hotnerds/badgeroad/login/jwt/JwtFilter.java b/src/main/java/com/hotnerds/badgeroad/login/jwt/JwtFilter.java new file mode 100644 index 0000000..db406f0 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/login/jwt/JwtFilter.java @@ -0,0 +1,52 @@ +package com.hotnerds.badgeroad.login.jwt; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.util.StringUtils; +import org.springframework.web.filter.GenericFilterBean; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; + +public class JwtFilter extends GenericFilterBean { + + private static final Logger logger = LoggerFactory.getLogger(JwtFilter.class); + public static final String AUTHORIZATION_HEADER = "Authorization"; + private TokenProvider tokenProvider; + public JwtFilter(TokenProvider tokenProvider) { + this.tokenProvider = tokenProvider; + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { + HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest; + String jwt = resolveToken(httpServletRequest); + String requestURI = httpServletRequest.getRequestURI(); + + if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) { + Authentication authentication = tokenProvider.getAuthentication(jwt); + SecurityContextHolder.getContext().setAuthentication(authentication); + logger.debug("Security Context에 '{}' 인증 정보를 저장했습니다, uri: {}", authentication.getName(), requestURI); + } else { + logger.debug("유효한 JWT 토큰이 없습니다, uri: {}", requestURI); + } + + filterChain.doFilter(servletRequest, servletResponse); + } + + private String resolveToken(HttpServletRequest request) { + String bearerToken = request.getHeader(AUTHORIZATION_HEADER); + + if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { + return bearerToken.substring(7); + } + + return null; + } +} diff --git a/src/main/java/com/hotnerds/badgeroad/login/jwt/JwtSecurityConfig.java b/src/main/java/com/hotnerds/badgeroad/login/jwt/JwtSecurityConfig.java new file mode 100644 index 0000000..a32a866 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/login/jwt/JwtSecurityConfig.java @@ -0,0 +1,21 @@ +package com.hotnerds.badgeroad.login.jwt; + +import org.springframework.security.config.annotation.SecurityConfigurerAdapter; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.web.DefaultSecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +public class JwtSecurityConfig extends SecurityConfigurerAdapter { + private TokenProvider tokenProvider; + public JwtSecurityConfig(TokenProvider tokenProvider) { + this.tokenProvider = tokenProvider; + } + + @Override + public void configure(HttpSecurity http) { + http.addFilterBefore( + new JwtFilter(tokenProvider), + UsernamePasswordAuthenticationFilter.class + ); + } +} diff --git a/src/main/java/com/hotnerds/badgeroad/login/jwt/TokenProvider.java b/src/main/java/com/hotnerds/badgeroad/login/jwt/TokenProvider.java new file mode 100644 index 0000000..73a80be --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/login/jwt/TokenProvider.java @@ -0,0 +1,94 @@ +package com.hotnerds.badgeroad.login.jwt; + +import io.jsonwebtoken.*; +import io.jsonwebtoken.io.Decoders; +import io.jsonwebtoken.security.Keys; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.User; +import org.springframework.stereotype.Component; + +import java.security.Key; +import java.util.Arrays; +import java.util.Collection; +import java.util.Date; +import java.util.stream.Collectors; + +@Component +public class TokenProvider implements InitializingBean { + + private final Logger logger = LoggerFactory.getLogger(TokenProvider.class); + private static final String AUTHORITIES_KEY = "auth"; + private final String secret; + private final long tokenValidityInMilliseconds; + private Key key; + + public TokenProvider( + @Value("${jwt.secret}") String secret, + @Value("${jwt.token-validity-in-seconds}") long tokenValidityInSeconds) { + this.secret = secret; + this.tokenValidityInMilliseconds = tokenValidityInSeconds * 1000; + } + + @Override + public void afterPropertiesSet() { + byte[] keyBytes = Decoders.BASE64.decode(secret); + this.key = Keys.hmacShaKeyFor(keyBytes); + } + + public String createToken(Authentication authentication) { + String authorities = authentication.getAuthorities().stream() + .map(GrantedAuthority::getAuthority) + .collect(Collectors.joining(",")); + + long now = (new Date()).getTime(); + Date validity = new Date(now + this.tokenValidityInMilliseconds); + + return Jwts.builder() + .setSubject(authentication.getName()) + .claim(AUTHORITIES_KEY, authorities) + .signWith(key, SignatureAlgorithm.HS512) + .setExpiration(validity) + .compact(); + } + + public Authentication getAuthentication(String token) { + Claims claims = Jwts + .parserBuilder() + .setSigningKey(key) + .build() + .parseClaimsJws(token) + .getBody(); + + Collection authorities = + Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(",")) + .map(SimpleGrantedAuthority::new) + .collect(Collectors.toList()); + + User principal = new User(claims.getSubject(), "", authorities); + + return new UsernamePasswordAuthenticationToken(principal, token, authorities); + } + + public boolean validateToken(String token) { + try { + Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token); + return true; + } catch (io.jsonwebtoken.security.SecurityException | MalformedJwtException e) { + logger.info("잘못된 JWT 서명입니다."); + } catch (ExpiredJwtException e) { + logger.info("만료된 JWT 토큰입니다."); + } catch (UnsupportedJwtException e) { + logger.info("지원되지 않는 JWT 토큰입니다."); + } catch (IllegalArgumentException e) { + logger.info("JWT 토큰이 잘못되었습니다."); + } + return false; + } +} diff --git a/src/main/java/com/hotnerds/badgeroad/login/repository/AuthorityRepository.java b/src/main/java/com/hotnerds/badgeroad/login/repository/AuthorityRepository.java new file mode 100644 index 0000000..b09d8b1 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/login/repository/AuthorityRepository.java @@ -0,0 +1,7 @@ +package com.hotnerds.badgeroad.login.repository; + +import com.hotnerds.badgeroad.login.entity.Authority; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface AuthorityRepository extends JpaRepository { +} diff --git a/src/main/java/com/hotnerds/badgeroad/login/repository/UserRepository.java b/src/main/java/com/hotnerds/badgeroad/login/repository/UserRepository.java new file mode 100644 index 0000000..d13828b --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/login/repository/UserRepository.java @@ -0,0 +1,12 @@ +package com.hotnerds.badgeroad.login.repository; + +import com.hotnerds.badgeroad.login.entity.User; +import org.springframework.data.jpa.repository.EntityGraph; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface UserRepository extends JpaRepository { + @EntityGraph(attributePaths = "authorities") + Optional findOneWithAuthoritiesByUsername(String username); +} diff --git a/src/main/java/com/hotnerds/badgeroad/login/service/CustomUserDetailsService.java b/src/main/java/com/hotnerds/badgeroad/login/service/CustomUserDetailsService.java new file mode 100644 index 0000000..3bfcf54 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/login/service/CustomUserDetailsService.java @@ -0,0 +1,45 @@ +package com.hotnerds.badgeroad.login.service; + +import com.hotnerds.badgeroad.login.entity.User; +import com.hotnerds.badgeroad.login.repository.UserRepository; +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.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.stream.Collectors; + +@Component("userDetailsService") +public class CustomUserDetailsService implements UserDetailsService { + private final UserRepository userRepository; + + public CustomUserDetailsService(UserRepository userRepository) { + this.userRepository = userRepository; + } + + @Override + @Transactional + public UserDetails loadUserByUsername(final String username) { + return userRepository.findOneWithAuthoritiesByUsername(username) + .map(user -> createUser(username, user)) + .orElseThrow(() -> new UsernameNotFoundException(username + " -> 데이터베이스에서 찾을 수 없습니다.")); + } + + private org.springframework.security.core.userdetails.User createUser(String username, User user) { + if (!user.isActivated()) { + throw new RuntimeException(username + " -> 활성화되어 있지 않습니다."); + } + + List grantedAuthorities = user.getAuthorities().stream() + .map(authority -> new SimpleGrantedAuthority(authority.getAuthorityName())) + .collect(Collectors.toList()); + + return new org.springframework.security.core.userdetails.User(user.getUsername(), + user.getPassword(), + grantedAuthorities); + } +} diff --git a/src/main/java/com/hotnerds/badgeroad/login/service/UserService.java b/src/main/java/com/hotnerds/badgeroad/login/service/UserService.java new file mode 100644 index 0000000..9dbf11e --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/login/service/UserService.java @@ -0,0 +1,60 @@ +package com.hotnerds.badgeroad.login.service; + +import com.hotnerds.badgeroad.login.dto.UserDto; +import com.hotnerds.badgeroad.login.entity.Authority; +import com.hotnerds.badgeroad.login.entity.User; +import com.hotnerds.badgeroad.login.exception.DuplicateMemberException; +import com.hotnerds.badgeroad.login.exception.NotFoundMemberException; +import com.hotnerds.badgeroad.login.repository.UserRepository; +import com.hotnerds.badgeroad.login.util.SecurityUtil; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collections; + +@Service +public class UserService { + private final UserRepository userRepository; + private final PasswordEncoder passwordEncoder; + + public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) { + this.userRepository = userRepository; + this.passwordEncoder = passwordEncoder; + } + + @Transactional + public UserDto signup(UserDto userDto) { + if (userRepository.findOneWithAuthoritiesByUsername(userDto.getUsername()).orElse(null) != null) { + throw new DuplicateMemberException("이미 가입되어 있는 유저입니다."); + } + + Authority authority = Authority.builder() + .authorityName("ROLE_USER") + .build(); + + User user = User.builder() + .username(userDto.getUsername()) + .password(passwordEncoder.encode(userDto.getPassword())) + .nickname(userDto.getNickname()) + .authorities(Collections.singleton(authority)) + .activated(true) + .build(); + + return UserDto.from(userRepository.save(user)); + } + + @Transactional(readOnly = true) + public UserDto getUserWithAuthorities(String username) { + return UserDto.from(userRepository.findOneWithAuthoritiesByUsername(username).orElse(null)); + } + + @Transactional(readOnly = true) + public UserDto getMyUserWithAuthorities() { + return UserDto.from( + SecurityUtil.getCurrentUsername() + .flatMap(userRepository::findOneWithAuthoritiesByUsername) + .orElseThrow(() -> new NotFoundMemberException("Member not found")) + ); + } +} diff --git a/src/main/java/com/hotnerds/badgeroad/login/util/SecurityUtil.java b/src/main/java/com/hotnerds/badgeroad/login/util/SecurityUtil.java new file mode 100644 index 0000000..669f663 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/login/util/SecurityUtil.java @@ -0,0 +1,35 @@ +package com.hotnerds.badgeroad.login.util; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; + +import java.util.Optional; + +public class SecurityUtil { + + private static final Logger logger = LoggerFactory.getLogger(SecurityUtil.class); + + private SecurityUtil() {} + + public static Optional getCurrentUsername() { + final Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + + if (authentication == null) { + logger.debug("Security Context에 인증 정보가 없습니다."); + return Optional.empty(); + } + + String username = null; + if (authentication.getPrincipal() instanceof UserDetails) { + UserDetails springSecurityUser = (UserDetails) authentication.getPrincipal(); + username = springSecurityUser.getUsername(); + } else if (authentication.getPrincipal() instanceof String) { + username = (String) authentication.getPrincipal(); + } + + return Optional.ofNullable(username); + } +} diff --git a/src/main/java/com/hotnerds/badgeroad/openapi/NaverClient.java b/src/main/java/com/hotnerds/badgeroad/openapi/NaverClient.java new file mode 100644 index 0000000..d0f34b0 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/openapi/NaverClient.java @@ -0,0 +1,243 @@ +package com.hotnerds.badgeroad.openapi; + +import com.hotnerds.badgeroad.openapi.dto.SearchImageReq; +import com.hotnerds.badgeroad.openapi.dto.SearchImageRes; +import com.hotnerds.badgeroad.openapi.dto.SearchLocalReq; +import com.hotnerds.badgeroad.openapi.dto.SearchLocalRes; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +import java.io.*; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLEncoder; +import java.util.HashMap; +import java.util.Map; + +@Component +public class NaverClient { + + // yaml 파일 사용하는데 @Value 어노테이션을 사용하며 + // 내부에 "${}"형태로 yaml에 설정한 대로 기입 + @Value("${NAVER-CLIENT}") + String naverClientId; + + @Value("${NAVER-KEY}") + String naverSecret; + + @Value("${naver.url.search.local}") + String naverLocalSearchUrl; + + @Value("${naver.url.search.blog}") + String naverBlogSearchUrl; + + @Value("${naver.url.search.image}") + String naverImageSearchUrl; + + public String searchBlog(String query) { + try { + query = URLEncoder.encode(query, "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException("검색어 인코딩 실패", e); + } + + String apiURL = naverBlogSearchUrl + + "?query=" + query; + + Map requestHeaders = new HashMap<>(); + requestHeaders.put("X-Naver-Client-Id", naverClientId); + requestHeaders.put("X-Naver-Client-Secret", naverSecret); + String responseBody = get(apiURL, requestHeaders); + System.out.println(responseBody); + + return responseBody; + } + + public String searchImage(String query) { + try { + query = URLEncoder.encode(query, "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException("검색어 인코딩 실패", e); + } + + String apiURL = naverImageSearchUrl + + "?query=" + query; + + Map requestHeaders = new HashMap<>(); + requestHeaders.put("X-Naver-Client-Id", naverClientId); + requestHeaders.put("X-Naver-Client-Secret", naverSecret); + String responseBody = get(apiURL, requestHeaders); + System.out.println(responseBody); + + return responseBody; + } + + public String searchLocal(String query) { + try { + query = URLEncoder.encode(query, "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException("검색어 인코딩 실패", e); + } + + String apiURL = naverLocalSearchUrl + + "?query=" + query; + SearchLocalReq searchLocalReq = new SearchLocalReq(); +// URI apiURL = ServletUriComponentsBuilder +// .fromUriString(naverLocalSearchUrl) +// .queryParams(searchLocalReq.toMultiValueMap()) +// .build() +// .encode() +// .toUri(); + + Map requestHeaders = new HashMap<>(); + requestHeaders.put("X-Naver-Client-Id", naverClientId); + requestHeaders.put("X-Naver-Client-Secret", naverSecret); + String responseBody = get(apiURL.toString(), requestHeaders); +// +// +// var uri = UriComponentsBuilder +// .fromUriString(naverLocalSearchUrl) +// .query(query) +// .queryParams(searchLocalReq.toMultiValueMap()) +// .build() +// .encode() +// .toUri(); +// +// System.out.println(apiURL); +// System.out.println(uri); + +// var headers = new HttpHeaders(); +// headers.set("X-Naver-Client-Id", naverClientId); +// headers.set("X-Naver-Client-Secret", naverSecret); +// headers.setContentType(MediaType.APPLICATION_JSON); +// +// var httpEntity = new HttpEntity<>(headers); +// var responseType = new ParameterizedTypeReference(){}; +// +// +// var responseEntity = new RestTemplate() +// .exchange( +// uri, +// HttpMethod.GET, +// httpEntity, +// responseType +// ); + + + return responseBody; + } + + private String get(String apiUrl, Map requestHeaders) { + HttpURLConnection con = connect(apiUrl); + + try { + con.setRequestMethod("GET"); + for (Map.Entry header: requestHeaders.entrySet()) { + con.setRequestProperty(header.getKey(), header.getValue()); + } + + int responseCode = con.getResponseCode(); + if (responseCode == HttpURLConnection.HTTP_OK) { + return readBody(con.getInputStream()); + } else { + return readBody(con.getErrorStream()); + } + } catch (IOException e) { + throw new RuntimeException("API 요청과 응답 실패", e); + } finally { + con.disconnect(); + } + } + + private HttpURLConnection connect(String apiUrl) { + try { + URL url = new URL(apiUrl); + return (HttpURLConnection)url.openConnection(); + } catch (MalformedURLException e) { + throw new RuntimeException("API URL이 잘못되었습니다. : " + apiUrl, e); + } catch (IOException e) { + throw new RuntimeException("연결이 실패했습니다. : " + apiUrl, e); + } + } + + private String readBody(InputStream body) { + InputStreamReader streamReader = new InputStreamReader(body); + + try (BufferedReader lineReader = new BufferedReader(streamReader)) { + StringBuilder responseBody = new StringBuilder(); + + String line; + while ((line = lineReader.readLine()) != null) { + responseBody.append(line); + } + + return responseBody.toString(); + } catch (IOException e) { + throw new RuntimeException("API 응답을 읽는 데 실패했습니다.", e); + } + } + + public SearchLocalRes searchLocal(SearchLocalReq searchLocalReq) { + var uri = UriComponentsBuilder + .fromUriString(naverLocalSearchUrl) + .queryParams(searchLocalReq.toMultiValueMap()) + .build() + .encode() + .toUri(); + + var headers = new HttpHeaders(); + headers.set("X-Naver-Client-Id", naverClientId); + headers.set("X-Naver-Client-Secret", naverSecret); + headers.setContentType(MediaType.APPLICATION_JSON); + + var httpEntity = new HttpEntity<>(headers); + var responseType = new ParameterizedTypeReference(){}; + + + var responseEntity = new RestTemplate() + .exchange( + uri, + HttpMethod.GET, + httpEntity, + responseType + ); + + return responseEntity.getBody(); + } + + public SearchImageRes searchImage(SearchImageReq searchImageReq) { + var uri = UriComponentsBuilder + .fromUriString(naverImageSearchUrl) + .queryParams(searchImageReq.toMultiValueMap()) + .build() + .encode() + .toUri(); + + var headers = new HttpHeaders(); + headers.set("X-Naver-Client-Id", naverClientId); + headers.set("X-Naver-Client-Secret", naverSecret); + headers.setContentType(MediaType.APPLICATION_JSON); + + var httpEntity = new HttpEntity<>(headers); + var responseType = new ParameterizedTypeReference(){}; + + + var responseEntity = new RestTemplate() + .exchange( + uri, + HttpMethod.GET, + httpEntity, + responseType + ); + + return responseEntity.getBody(); + } +} \ No newline at end of file diff --git a/src/main/java/com/hotnerds/badgeroad/openapi/OpenApiController.java b/src/main/java/com/hotnerds/badgeroad/openapi/OpenApiController.java new file mode 100644 index 0000000..f987658 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/openapi/OpenApiController.java @@ -0,0 +1,41 @@ +package com.hotnerds.badgeroad.openapi; + +import lombok.RequiredArgsConstructor; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RequiredArgsConstructor +@RestController +@RequestMapping("/openapi") +public class OpenApiController { + @Autowired + NaverClient naver = new NaverClient(); + + @ResponseBody + @GetMapping("naver/blog") + public ResponseEntity getPlace(@RequestParam("query") String query) throws Exception { + JSONParser parser = new JSONParser(); + Object obj = parser.parse(naver.searchBlog(query)); + JSONObject jsonObj = (JSONObject) obj; + return ResponseEntity.ok(jsonObj); + } + + @ResponseBody + @GetMapping("/naver/image") + public ResponseEntity getImage(@RequestParam("query") String query) throws Exception { + JSONParser parser = new JSONParser(); + JSONObject jsonObj = (JSONObject)parser.parse(naver.searchImage(query)); + return ResponseEntity.ok(jsonObj); + } + + @ResponseBody + @GetMapping("/naver/local") + public ResponseEntity getLocal(@RequestParam("query") String query) throws Exception { + JSONParser parser = new JSONParser(); + JSONObject jsonObj = (JSONObject)parser.parse(naver.searchLocal(query)); + return ResponseEntity.ok(jsonObj); + } +} diff --git a/src/main/java/com/hotnerds/badgeroad/openapi/dto/SearchImageReq.java b/src/main/java/com/hotnerds/badgeroad/openapi/dto/SearchImageReq.java new file mode 100644 index 0000000..f457fb4 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/openapi/dto/SearchImageReq.java @@ -0,0 +1,35 @@ +package com.hotnerds.badgeroad.openapi.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class SearchImageReq { + // 지역 검색 요청 변수에 대한 변수 생성 + private String query = ""; + private int display = 1; // 검색 결과 출력 건수 지정(10 ~ 100) + + private int start = 1; // 검색 시작 위치로 최대 1000까지 가능 + + private String sort = "sim"; // 정렬 옵션: sim (유사도순), date (날짜순) + + private String filter = "all "; // 사이즈 필터 옵션: all(전체), large(큰 사이즈), medium(중간 사이즈), small(작은 사이즈) + + public MultiValueMap toMultiValueMap() { + var map = new LinkedMultiValueMap(); + + map.add("query", query); + map.add("display", String.valueOf(display)); + map.add("start", String.valueOf(start)); + map.add("sort", sort); + map.add("filter", filter); + + return map; + + } +} diff --git a/src/main/java/com/hotnerds/badgeroad/openapi/dto/SearchImageRes.java b/src/main/java/com/hotnerds/badgeroad/openapi/dto/SearchImageRes.java new file mode 100644 index 0000000..278dd66 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/openapi/dto/SearchImageRes.java @@ -0,0 +1,28 @@ +package com.hotnerds.badgeroad.openapi.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +public class SearchImageRes { + // 지역 검색 출력 결과를 변수화 + + private String lastBuildDate; // 검색 결과를 생성한 시간이다. + private int total; // 검색 결과 문서의 총 개수를 의미한다. + private int start; // 검색 결과 문서 중, 문서의 시작점을 의미한다. + private int display; // 검색된 검색 결과의 개수이다. + private List items; // XML 포멧에서는 item 태그로, JSON 포멧에서는 items 속성으로 표현된다. 개별 검색 결과이며 title, link, description, address, mapx, mapy를 포함한다. + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class SearchImageItem{ + private String title; // 검색 결과 업체, 기관명을 나타낸다. + private String link; // 검색 결과 업체, 기관의 상세 정보가 제공되는 네이버 페이지의 하이퍼텍스트 link를 나타낸다. + private String thumbnail; // 검색 결과 이미지의 썸네일 link를 나타낸다. + private String sizeheight; // 검색 결과 이미지의 썸네일 높이를 나타낸다. + private String sizewidth; // 검색 결과 이미지의 너비를 나타낸다. 단위는 pixel이다. + } +} diff --git a/src/main/java/com/hotnerds/badgeroad/openapi/dto/SearchLocalReq.java b/src/main/java/com/hotnerds/badgeroad/openapi/dto/SearchLocalReq.java new file mode 100644 index 0000000..0d3190f --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/openapi/dto/SearchLocalReq.java @@ -0,0 +1,32 @@ +package com.hotnerds.badgeroad.openapi.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class SearchLocalReq { + // 지역 검색 요청 변수에 대한 변수 생성 + private String query = ""; + private int display = 1; // 검색 결과 출력 건수 지정(1 ~ 5) + + private int start = 1; // 검색 시작 위치로 1만 가능 + + private String sort = "random"; // 정렬 옵션: random(유사도순), comment(카페/블로그 리뷰 개수 순) + + public MultiValueMap toMultiValueMap() { + var map = new LinkedMultiValueMap(); + + map.add("query", query); + map.add("display", String.valueOf(display)); + map.add("start", String.valueOf(start)); + map.add("sort", sort); + + return map; + + } +} diff --git a/src/main/java/com/hotnerds/badgeroad/openapi/dto/SearchLocalRes.java b/src/main/java/com/hotnerds/badgeroad/openapi/dto/SearchLocalRes.java new file mode 100644 index 0000000..df7f7a3 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/openapi/dto/SearchLocalRes.java @@ -0,0 +1,36 @@ +package com.hotnerds.badgeroad.openapi.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class SearchLocalRes { + + // 지역 검색 출력 결과를 변수화 + + private String lastBuildDate; // 검색 결과를 생성한 시간이다. + private int total; // 검색 결과 문서의 총 개수를 의미한다. + private int start; // 검색 결과 문서 중, 문서의 시작점을 의미한다. + private int display; // 검색된 검색 결과의 개수이다. + private List items; // XML 포멧에서는 item 태그로, JSON 포멧에서는 items 속성으로 표현된다. 개별 검색 결과이며 title, link, description, address, mapx, mapy를 포함한다. + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class SearchLocalItem{ + private String title; // 검색 결과 업체, 기관명을 나타낸다. + private String link; // 검색 결과 업체, 기관의 상세 정보가 제공되는 네이버 페이지의 하이퍼텍스트 link를 나타낸다. + private String category; // 검색 결과 업체, 기관의 분류 정보를 제공한다. + private String description; // 검색 결과 업체, 기관명에 대한 설명을 제공한다. + private String telephone; // 빈 문자열 반환. 과거에 제공되던 항목이라 하위 호환성을 위해 존재한다. + private String address; // 검색 결과 업체, 기관명의 주소를 제공한다. + private String roadAddress; // 검색 결과 업체, 기관명의 도로명 주소를 제공한다. + private int mapx; // 검색 결과 업체, 기관명 위치 정보의 x좌표를 제공한다. 제공값은 카텍좌표계 값으로 제공된다. 이 좌표값은 지도 API와 연동 가능하다. + private int mapy; // 검색 결과 업체, 기관명 위치 정보의 y좌표를 제공한다. 제공값은 카텍 좌표계 값으로 제공된다. 이 좌표값은 지도 API와 연동 가능하다. + } +} \ No newline at end of file diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql new file mode 100644 index 0000000..1af28c6 --- /dev/null +++ b/src/main/resources/data.sql @@ -0,0 +1,9 @@ +insert into user (username, password, nickname, activated) values ('admin', '$2a$08$lDnHPz7eUkSi6ao14Twuau08mzhWrL4kyZGGU5xfiGALO/Vxd5DOi', 'admin', 1); +insert into user (username, password, nickname, activated) values ('user', '$2a$08$UkVvwpULis18S19S5pZFn.YHPZt3oaqHZnDwqbCW9pft6uFtkXKDC', 'user', 1); + +insert into authority (authority_name) values ('ROLE_USER'); +insert into authority (authority_name) values ('ROLE_ADMIN'); + +insert into user_authority (user_id, authority_name) values (1, 'ROLE_USER'); +insert into user_authority (user_id, authority_name) values (1, 'ROLE_ADMIN'); +insert into user_authority (user_id, authority_name) values (2, 'ROLE_USER'); \ No newline at end of file From 131a263389f00ea089976cd10d1caefae4d676e3 Mon Sep 17 00:00:00 2001 From: shinjbin Date: Thu, 15 Dec 2022 00:16:13 +0900 Subject: [PATCH 03/11] init --- pom.xml | 4 + .../badgeroad/home/LoginSignupController.java | 20 ---- .../badgeroad/login/config/CorsConfig.java | 23 ---- .../login/config/SecurityConfig.java | 89 --------------- .../login/controller/AuthController.java | 48 --------- .../badgeroad/login/dto/AuthorityDto.java | 12 --- .../badgeroad/login/dto/ErrorDto.java | 34 ------ .../badgeroad/login/dto/TokenDto.java | 13 --- .../hotnerds/badgeroad/login/entity/User.java | 40 ------- ...ethodArgumentNotValidExceptionHandler.java | 37 ------- .../handler/RestResponseExceptionHandler.java | 33 ------ .../login/jwt/JwtAccessDeniedHandler.java | 18 ---- .../jwt/JwtAuthenticationEntryPoint.java | 20 ---- .../badgeroad/login/jwt/JwtFilter.java | 52 --------- .../login/jwt/JwtSecurityConfig.java | 21 ---- .../badgeroad/login/jwt/TokenProvider.java | 94 ---------------- .../login/repository/AuthorityRepository.java | 7 -- .../service/CustomUserDetailsService.java | 45 -------- .../badgeroad/login/service/UserService.java | 60 ----------- .../controller/UserController.java | 36 ++++--- .../{login => user}/dto/LoginDto.java | 2 +- .../badgeroad/user/dto/SignupDto.java | 4 + .../{login => user}/dto/UserDto.java | 17 ++- .../{login => user}/entity/Authority.java | 2 +- .../hotnerds/badgeroad/user/entity/User.java | 31 ++++++ .../exception/DuplicateMemberException.java | 2 +- .../exception/NotFoundMemberException.java | 2 +- .../repository/UserRepository.java | 6 +- .../badgeroad/user/service/UserService.java | 44 ++++++++ .../{login => user}/util/SecurityUtil.java | 2 +- src/main/resources/templates/common.html | 35 ++++++ src/main/resources/templates/index.html | 12 +++ src/main/resources/templates/login.html | 102 ++++++++++++++++++ src/main/resources/templates/members.html | 54 ++++++++++ src/main/resources/templates/signup.html | 74 +++++++++++++ src/main/resources/templates/user_access.html | 13 +++ .../trash/config/SecurityConfig.java | 98 +++++++++++++++++ .../trash/controller/AuthController.java | 77 +++++++++++++ .../trash/controller/HomeController.java | 8 ++ src/main/resources/trash/dto/MemberDto.java | 25 +++++ .../trash/dto/MemberSignupRequestDto.java | 12 +++ src/main/resources/trash/entity/Member.java | 41 +++++++ src/main/resources/trash/entity/Role.java | 28 +++++ src/main/resources/trash/login.html | 76 +++++++++++++ .../trash/repository/MemberRepository.java | 9 ++ .../trash/repository/RoleRepository.java | 8 ++ .../service/CustomUserDetailsService.java | 43 ++++++++ .../trash/service/MemberService.java | 14 +++ .../trash/service/MemberServiceImpl.java | 72 +++++++++++++ .../trash/yamlreadDB/ApplicationDBRead.java | 18 ++++ .../resources/trash/yamlreadDB/DBSource.java | 17 +++ .../yamlreadDB/YamlPropertySourceFactory.java | 37 +++++++ 52 files changed, 991 insertions(+), 700 deletions(-) delete mode 100644 src/main/java/com/hotnerds/badgeroad/home/LoginSignupController.java delete mode 100644 src/main/java/com/hotnerds/badgeroad/login/config/CorsConfig.java delete mode 100644 src/main/java/com/hotnerds/badgeroad/login/config/SecurityConfig.java delete mode 100644 src/main/java/com/hotnerds/badgeroad/login/controller/AuthController.java delete mode 100644 src/main/java/com/hotnerds/badgeroad/login/dto/AuthorityDto.java delete mode 100644 src/main/java/com/hotnerds/badgeroad/login/dto/ErrorDto.java delete mode 100644 src/main/java/com/hotnerds/badgeroad/login/dto/TokenDto.java delete mode 100644 src/main/java/com/hotnerds/badgeroad/login/entity/User.java delete mode 100644 src/main/java/com/hotnerds/badgeroad/login/handler/MethodArgumentNotValidExceptionHandler.java delete mode 100644 src/main/java/com/hotnerds/badgeroad/login/handler/RestResponseExceptionHandler.java delete mode 100644 src/main/java/com/hotnerds/badgeroad/login/jwt/JwtAccessDeniedHandler.java delete mode 100644 src/main/java/com/hotnerds/badgeroad/login/jwt/JwtAuthenticationEntryPoint.java delete mode 100644 src/main/java/com/hotnerds/badgeroad/login/jwt/JwtFilter.java delete mode 100644 src/main/java/com/hotnerds/badgeroad/login/jwt/JwtSecurityConfig.java delete mode 100644 src/main/java/com/hotnerds/badgeroad/login/jwt/TokenProvider.java delete mode 100644 src/main/java/com/hotnerds/badgeroad/login/repository/AuthorityRepository.java delete mode 100644 src/main/java/com/hotnerds/badgeroad/login/service/CustomUserDetailsService.java delete mode 100644 src/main/java/com/hotnerds/badgeroad/login/service/UserService.java rename src/main/java/com/hotnerds/badgeroad/{login => user}/controller/UserController.java (56%) rename src/main/java/com/hotnerds/badgeroad/{login => user}/dto/LoginDto.java (88%) create mode 100644 src/main/java/com/hotnerds/badgeroad/user/dto/SignupDto.java rename src/main/java/com/hotnerds/badgeroad/{login => user}/dto/UserDto.java (55%) rename src/main/java/com/hotnerds/badgeroad/{login => user}/entity/Authority.java (88%) create mode 100644 src/main/java/com/hotnerds/badgeroad/user/entity/User.java rename src/main/java/com/hotnerds/badgeroad/{login => user}/exception/DuplicateMemberException.java (89%) rename src/main/java/com/hotnerds/badgeroad/{login => user}/exception/NotFoundMemberException.java (89%) rename src/main/java/com/hotnerds/badgeroad/{login => user}/repository/UserRepository.java (61%) create mode 100644 src/main/java/com/hotnerds/badgeroad/user/service/UserService.java rename src/main/java/com/hotnerds/badgeroad/{login => user}/util/SecurityUtil.java (96%) create mode 100644 src/main/resources/templates/common.html create mode 100644 src/main/resources/templates/index.html create mode 100644 src/main/resources/templates/login.html create mode 100644 src/main/resources/templates/members.html create mode 100644 src/main/resources/templates/signup.html create mode 100644 src/main/resources/templates/user_access.html create mode 100644 src/main/resources/trash/config/SecurityConfig.java create mode 100644 src/main/resources/trash/controller/AuthController.java create mode 100644 src/main/resources/trash/controller/HomeController.java create mode 100644 src/main/resources/trash/dto/MemberDto.java create mode 100644 src/main/resources/trash/dto/MemberSignupRequestDto.java create mode 100644 src/main/resources/trash/entity/Member.java create mode 100644 src/main/resources/trash/entity/Role.java create mode 100644 src/main/resources/trash/login.html create mode 100644 src/main/resources/trash/repository/MemberRepository.java create mode 100644 src/main/resources/trash/repository/RoleRepository.java create mode 100644 src/main/resources/trash/service/CustomUserDetailsService.java create mode 100644 src/main/resources/trash/service/MemberService.java create mode 100644 src/main/resources/trash/service/MemberServiceImpl.java create mode 100644 src/main/resources/trash/yamlreadDB/ApplicationDBRead.java create mode 100644 src/main/resources/trash/yamlreadDB/DBSource.java create mode 100644 src/main/resources/trash/yamlreadDB/YamlPropertySourceFactory.java diff --git a/pom.xml b/pom.xml index 64387ab..4fd6958 100644 --- a/pom.xml +++ b/pom.xml @@ -51,6 +51,10 @@ spring-boot-starter-test test + + org.springframework.boot + spring-boot-starter-validation + diff --git a/src/main/java/com/hotnerds/badgeroad/home/LoginSignupController.java b/src/main/java/com/hotnerds/badgeroad/home/LoginSignupController.java deleted file mode 100644 index 14ec00f..0000000 --- a/src/main/java/com/hotnerds/badgeroad/home/LoginSignupController.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.hotnerds.badgeroad.home; - -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; - -@Controller -@RequestMapping("/user") -public class LoginSignupController { - - @GetMapping("/login") - public String login() { - return "login"; - } - - @GetMapping("/signup") - public String signup() { - return "signup"; - } -} diff --git a/src/main/java/com/hotnerds/badgeroad/login/config/CorsConfig.java b/src/main/java/com/hotnerds/badgeroad/login/config/CorsConfig.java deleted file mode 100644 index c1cf3a6..0000000 --- a/src/main/java/com/hotnerds/badgeroad/login/config/CorsConfig.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.hotnerds.badgeroad.login.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.cors.CorsConfiguration; -import org.springframework.web.cors.UrlBasedCorsConfigurationSource; -import org.springframework.web.filter.CorsFilter; - -@Configuration -public class CorsConfig { - @Bean - public CorsFilter corsFilter() { - UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); - CorsConfiguration config = new CorsConfiguration(); - config.setAllowCredentials(true); - config.addAllowedOrigin("*"); - config.addAllowedHeader("*"); - config.addAllowedMethod("*"); - - source.registerCorsConfiguration("/api/**", config); - return new CorsFilter(source); - } -} diff --git a/src/main/java/com/hotnerds/badgeroad/login/config/SecurityConfig.java b/src/main/java/com/hotnerds/badgeroad/login/config/SecurityConfig.java deleted file mode 100644 index 0da8d89..0000000 --- a/src/main/java/com/hotnerds/badgeroad/login/config/SecurityConfig.java +++ /dev/null @@ -1,89 +0,0 @@ -package com.hotnerds.badgeroad.login.config; - -import com.hotnerds.badgeroad.login.jwt.JwtAccessDeniedHandler; -import com.hotnerds.badgeroad.login.jwt.JwtAuthenticationEntryPoint; -import com.hotnerds.badgeroad.login.jwt.JwtSecurityConfig; -import com.hotnerds.badgeroad.login.jwt.TokenProvider; -import org.springframework.context.annotation.Bean; -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; -import org.springframework.web.filter.CorsFilter; - -@EnableWebSecurity -@EnableGlobalMethodSecurity(prePostEnabled = true) -public class SecurityConfig { - private final TokenProvider tokenProvider; - private final CorsFilter corsFilter; - private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; - private final JwtAccessDeniedHandler jwtAccessDeniedHandler; - - public SecurityConfig( - TokenProvider tokenProvider, - CorsFilter corsFilter, - JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint, - JwtAccessDeniedHandler jwtAccessDeniedHandler - ) { - this.tokenProvider = tokenProvider; - this.corsFilter = corsFilter; - this.jwtAuthenticationEntryPoint = jwtAuthenticationEntryPoint; - this.jwtAccessDeniedHandler = jwtAccessDeniedHandler; - } - - @Bean - public PasswordEncoder passwordEncoder() { - return new BCryptPasswordEncoder(); - } - - @Bean - public WebSecurityCustomizer webSecurityCustomizer() { - return (web) -> web.ignoring().antMatchers("/h2-console/**" - , "/favicon.ico" - , "/error"); - } - - @Bean - public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { - httpSecurity - // token을 사용하는 방식이기 때문에 csrf를 disable합니다. - .csrf().disable() - - .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class) - - .exceptionHandling() - .authenticationEntryPoint(jwtAuthenticationEntryPoint) - .accessDeniedHandler(jwtAccessDeniedHandler) - - // enable h2-console - .and() - .headers() - .frameOptions() - .sameOrigin() - - // 세션을 사용하지 않기 때문에 STATELESS로 설정 - .and() - .sessionManagement() - .sessionCreationPolicy(SessionCreationPolicy.STATELESS) - - .and() - .authorizeRequests() - .antMatchers("/").permitAll() - .antMatchers("/user/**").permitAll() - .antMatchers("/api/hello").permitAll() - .antMatchers("/api/authenticate").permitAll() - .antMatchers("/api/signup").permitAll() - - .anyRequest().authenticated() - - .and() - .apply(new JwtSecurityConfig(tokenProvider)); - - return httpSecurity.build(); - } -} \ No newline at end of file diff --git a/src/main/java/com/hotnerds/badgeroad/login/controller/AuthController.java b/src/main/java/com/hotnerds/badgeroad/login/controller/AuthController.java deleted file mode 100644 index 1516278..0000000 --- a/src/main/java/com/hotnerds/badgeroad/login/controller/AuthController.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.hotnerds.badgeroad.login.controller; - -import com.hotnerds.badgeroad.login.dto.LoginDto; -import com.hotnerds.badgeroad.login.dto.TokenDto; -import com.hotnerds.badgeroad.login.jwt.JwtFilter; -import com.hotnerds.badgeroad.login.jwt.TokenProvider; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -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 javax.validation.Valid; - -@RestController -@RequestMapping("/api") -public class AuthController { - private final TokenProvider tokenProvider; - private final AuthenticationManagerBuilder authenticationManagerBuilder; - - public AuthController(TokenProvider tokenProvider, AuthenticationManagerBuilder authenticationManagerBuilder) { - this.tokenProvider = tokenProvider; - this.authenticationManagerBuilder = authenticationManagerBuilder; - } - - @PostMapping("/authenticate") - public ResponseEntity authorize(@Valid @RequestBody LoginDto loginDto) { - - UsernamePasswordAuthenticationToken authenticationToken = - new UsernamePasswordAuthenticationToken(loginDto.getUsername(), loginDto.getPassword()); - - Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken); - SecurityContextHolder.getContext().setAuthentication(authentication); - - String jwt = tokenProvider.createToken(authentication); - - HttpHeaders httpHeaders = new HttpHeaders(); - httpHeaders.add(JwtFilter.AUTHORIZATION_HEADER, "Bearer " + jwt); - - return new ResponseEntity<>(new TokenDto(jwt), httpHeaders, HttpStatus.OK); - } -} diff --git a/src/main/java/com/hotnerds/badgeroad/login/dto/AuthorityDto.java b/src/main/java/com/hotnerds/badgeroad/login/dto/AuthorityDto.java deleted file mode 100644 index a809175..0000000 --- a/src/main/java/com/hotnerds/badgeroad/login/dto/AuthorityDto.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.hotnerds.badgeroad.login.dto; - -import lombok.*; - -@Getter -@Setter -@Builder -@AllArgsConstructor -@NoArgsConstructor -public class AuthorityDto { - private String authorityName; -} \ No newline at end of file diff --git a/src/main/java/com/hotnerds/badgeroad/login/dto/ErrorDto.java b/src/main/java/com/hotnerds/badgeroad/login/dto/ErrorDto.java deleted file mode 100644 index 82b6e17..0000000 --- a/src/main/java/com/hotnerds/badgeroad/login/dto/ErrorDto.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.hotnerds.badgeroad.login.dto; - -import org.springframework.validation.FieldError; - -import java.util.ArrayList; -import java.util.List; - -public class ErrorDto { - private final int status; - private final String message; - private List fieldErrors = new ArrayList<>(); - - public ErrorDto(int status, String message) { - this.status = status; - this.message = message; - } - - public int getStatus() { - return status; - } - - public String getMessage() { - return message; - } - - public void addFieldError(String objectName, String path, String message) { - FieldError error = new FieldError(objectName, path, message); - fieldErrors.add(error); - } - - public List getFieldErrors() { - return fieldErrors; - } -} diff --git a/src/main/java/com/hotnerds/badgeroad/login/dto/TokenDto.java b/src/main/java/com/hotnerds/badgeroad/login/dto/TokenDto.java deleted file mode 100644 index d7ad345..0000000 --- a/src/main/java/com/hotnerds/badgeroad/login/dto/TokenDto.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.hotnerds.badgeroad.login.dto; - -import lombok.*; - -@Getter -@Setter -@Builder -@AllArgsConstructor -@NoArgsConstructor -public class TokenDto { - - private String token; -} diff --git a/src/main/java/com/hotnerds/badgeroad/login/entity/User.java b/src/main/java/com/hotnerds/badgeroad/login/entity/User.java deleted file mode 100644 index 783a15a..0000000 --- a/src/main/java/com/hotnerds/badgeroad/login/entity/User.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.hotnerds.badgeroad.login.entity; - -import lombok.*; - -import javax.persistence.*; -import java.util.Set; - -@Entity -@Table(name = "`user`") -@Getter -@Setter -@Builder -@AllArgsConstructor -@NoArgsConstructor -public class User { - - @Id - @Column(name = "user_id") - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long userId; - - @Column(name = "username", length = 50, unique = true) - private String username; - - @Column(name = "password", length = 100) - private String password; - - @Column(name = "nickname", length = 50) - private String nickname; - - @Column(name = "activated") - private boolean activated; - - @ManyToMany - @JoinTable( - name = "user_authority", - joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "user_id")}, - inverseJoinColumns = {@JoinColumn(name = "authority_name", referencedColumnName = "authority_name")}) - private Set authorities; -} diff --git a/src/main/java/com/hotnerds/badgeroad/login/handler/MethodArgumentNotValidExceptionHandler.java b/src/main/java/com/hotnerds/badgeroad/login/handler/MethodArgumentNotValidExceptionHandler.java deleted file mode 100644 index 3404716..0000000 --- a/src/main/java/com/hotnerds/badgeroad/login/handler/MethodArgumentNotValidExceptionHandler.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.hotnerds.badgeroad.login.handler; - -import com.hotnerds.badgeroad.login.dto.ErrorDto; -import org.springframework.core.Ordered; -import org.springframework.core.annotation.Order; -import org.springframework.validation.BindingResult; -import org.springframework.web.bind.MethodArgumentNotValidException; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.ResponseStatus; - -import java.util.List; - -import static org.springframework.http.HttpStatus.BAD_REQUEST; - -@Order(Ordered.HIGHEST_PRECEDENCE) -@ControllerAdvice -public class MethodArgumentNotValidExceptionHandler { - - @ResponseStatus(BAD_REQUEST) - @ResponseBody - @ExceptionHandler(MethodArgumentNotValidException.class) - public ErrorDto methodArgumentNotValidException(MethodArgumentNotValidException ex) { - BindingResult result = ex.getBindingResult(); - List fieldErrors = result.getFieldErrors(); - return processFieldErrors(fieldErrors); - } - - private ErrorDto processFieldErrors(List fieldErrors) { - ErrorDto errorDTO = new ErrorDto(BAD_REQUEST.value(), "@Valid Error"); - for (org.springframework.validation.FieldError fieldError: fieldErrors) { - errorDTO.addFieldError(fieldError.getObjectName(), fieldError.getField(), fieldError.getDefaultMessage()); - } - return errorDTO; - } -} \ No newline at end of file diff --git a/src/main/java/com/hotnerds/badgeroad/login/handler/RestResponseExceptionHandler.java b/src/main/java/com/hotnerds/badgeroad/login/handler/RestResponseExceptionHandler.java deleted file mode 100644 index 82885b3..0000000 --- a/src/main/java/com/hotnerds/badgeroad/login/handler/RestResponseExceptionHandler.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.hotnerds.badgeroad.login.handler; - -import com.hotnerds.badgeroad.login.dto.ErrorDto; -import com.hotnerds.badgeroad.login.exception.DuplicateMemberException; -import com.hotnerds.badgeroad.login.exception.NotFoundMemberException; -import org.springframework.security.access.AccessDeniedException; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.ResponseStatus; -import org.springframework.web.context.request.WebRequest; -import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; - -import static org.springframework.http.HttpStatus.CONFLICT; -import static org.springframework.http.HttpStatus.FORBIDDEN; - -@ControllerAdvice -public class RestResponseExceptionHandler extends ResponseEntityExceptionHandler { - - @ResponseStatus(CONFLICT) - @ExceptionHandler(value = { DuplicateMemberException.class }) - @ResponseBody - protected ErrorDto badRequest(RuntimeException ex, WebRequest request) { - return new ErrorDto(CONFLICT.value(), ex.getMessage()); - } - - @ResponseStatus(FORBIDDEN) - @ExceptionHandler(value = { NotFoundMemberException.class, AccessDeniedException.class }) - @ResponseBody - protected ErrorDto forbidden(RuntimeException ex, WebRequest request) { - return new ErrorDto(FORBIDDEN.value(), ex.getMessage()); - } -} \ No newline at end of file diff --git a/src/main/java/com/hotnerds/badgeroad/login/jwt/JwtAccessDeniedHandler.java b/src/main/java/com/hotnerds/badgeroad/login/jwt/JwtAccessDeniedHandler.java deleted file mode 100644 index c1cc447..0000000 --- a/src/main/java/com/hotnerds/badgeroad/login/jwt/JwtAccessDeniedHandler.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.hotnerds.badgeroad.login.jwt; - -import org.springframework.security.access.AccessDeniedException; -import org.springframework.security.web.access.AccessDeniedHandler; -import org.springframework.stereotype.Component; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; - -@Component -public class JwtAccessDeniedHandler implements AccessDeniedHandler { - @Override - public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException { - //필요한 권한이 없이 접근하려 할때 403 - response.sendError(HttpServletResponse.SC_FORBIDDEN); - } -} diff --git a/src/main/java/com/hotnerds/badgeroad/login/jwt/JwtAuthenticationEntryPoint.java b/src/main/java/com/hotnerds/badgeroad/login/jwt/JwtAuthenticationEntryPoint.java deleted file mode 100644 index 9fabc64..0000000 --- a/src/main/java/com/hotnerds/badgeroad/login/jwt/JwtAuthenticationEntryPoint.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.hotnerds.badgeroad.login.jwt; - -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.web.AuthenticationEntryPoint; -import org.springframework.stereotype.Component; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; - -@Component -public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { - @Override - public void commence(HttpServletRequest request, - HttpServletResponse response, - AuthenticationException authException) throws IOException { - // 유효한 자격증명을 제공하지 않고 접근하려 할때 401 - response.sendError(HttpServletResponse.SC_UNAUTHORIZED); - } -} diff --git a/src/main/java/com/hotnerds/badgeroad/login/jwt/JwtFilter.java b/src/main/java/com/hotnerds/badgeroad/login/jwt/JwtFilter.java deleted file mode 100644 index db406f0..0000000 --- a/src/main/java/com/hotnerds/badgeroad/login/jwt/JwtFilter.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.hotnerds.badgeroad.login.jwt; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.util.StringUtils; -import org.springframework.web.filter.GenericFilterBean; - -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; - -public class JwtFilter extends GenericFilterBean { - - private static final Logger logger = LoggerFactory.getLogger(JwtFilter.class); - public static final String AUTHORIZATION_HEADER = "Authorization"; - private TokenProvider tokenProvider; - public JwtFilter(TokenProvider tokenProvider) { - this.tokenProvider = tokenProvider; - } - - @Override - public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { - HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest; - String jwt = resolveToken(httpServletRequest); - String requestURI = httpServletRequest.getRequestURI(); - - if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) { - Authentication authentication = tokenProvider.getAuthentication(jwt); - SecurityContextHolder.getContext().setAuthentication(authentication); - logger.debug("Security Context에 '{}' 인증 정보를 저장했습니다, uri: {}", authentication.getName(), requestURI); - } else { - logger.debug("유효한 JWT 토큰이 없습니다, uri: {}", requestURI); - } - - filterChain.doFilter(servletRequest, servletResponse); - } - - private String resolveToken(HttpServletRequest request) { - String bearerToken = request.getHeader(AUTHORIZATION_HEADER); - - if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { - return bearerToken.substring(7); - } - - return null; - } -} diff --git a/src/main/java/com/hotnerds/badgeroad/login/jwt/JwtSecurityConfig.java b/src/main/java/com/hotnerds/badgeroad/login/jwt/JwtSecurityConfig.java deleted file mode 100644 index a32a866..0000000 --- a/src/main/java/com/hotnerds/badgeroad/login/jwt/JwtSecurityConfig.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.hotnerds.badgeroad.login.jwt; - -import org.springframework.security.config.annotation.SecurityConfigurerAdapter; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.web.DefaultSecurityFilterChain; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; - -public class JwtSecurityConfig extends SecurityConfigurerAdapter { - private TokenProvider tokenProvider; - public JwtSecurityConfig(TokenProvider tokenProvider) { - this.tokenProvider = tokenProvider; - } - - @Override - public void configure(HttpSecurity http) { - http.addFilterBefore( - new JwtFilter(tokenProvider), - UsernamePasswordAuthenticationFilter.class - ); - } -} diff --git a/src/main/java/com/hotnerds/badgeroad/login/jwt/TokenProvider.java b/src/main/java/com/hotnerds/badgeroad/login/jwt/TokenProvider.java deleted file mode 100644 index 73a80be..0000000 --- a/src/main/java/com/hotnerds/badgeroad/login/jwt/TokenProvider.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.hotnerds.badgeroad.login.jwt; - -import io.jsonwebtoken.*; -import io.jsonwebtoken.io.Decoders; -import io.jsonwebtoken.security.Keys; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.userdetails.User; -import org.springframework.stereotype.Component; - -import java.security.Key; -import java.util.Arrays; -import java.util.Collection; -import java.util.Date; -import java.util.stream.Collectors; - -@Component -public class TokenProvider implements InitializingBean { - - private final Logger logger = LoggerFactory.getLogger(TokenProvider.class); - private static final String AUTHORITIES_KEY = "auth"; - private final String secret; - private final long tokenValidityInMilliseconds; - private Key key; - - public TokenProvider( - @Value("${jwt.secret}") String secret, - @Value("${jwt.token-validity-in-seconds}") long tokenValidityInSeconds) { - this.secret = secret; - this.tokenValidityInMilliseconds = tokenValidityInSeconds * 1000; - } - - @Override - public void afterPropertiesSet() { - byte[] keyBytes = Decoders.BASE64.decode(secret); - this.key = Keys.hmacShaKeyFor(keyBytes); - } - - public String createToken(Authentication authentication) { - String authorities = authentication.getAuthorities().stream() - .map(GrantedAuthority::getAuthority) - .collect(Collectors.joining(",")); - - long now = (new Date()).getTime(); - Date validity = new Date(now + this.tokenValidityInMilliseconds); - - return Jwts.builder() - .setSubject(authentication.getName()) - .claim(AUTHORITIES_KEY, authorities) - .signWith(key, SignatureAlgorithm.HS512) - .setExpiration(validity) - .compact(); - } - - public Authentication getAuthentication(String token) { - Claims claims = Jwts - .parserBuilder() - .setSigningKey(key) - .build() - .parseClaimsJws(token) - .getBody(); - - Collection authorities = - Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(",")) - .map(SimpleGrantedAuthority::new) - .collect(Collectors.toList()); - - User principal = new User(claims.getSubject(), "", authorities); - - return new UsernamePasswordAuthenticationToken(principal, token, authorities); - } - - public boolean validateToken(String token) { - try { - Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token); - return true; - } catch (io.jsonwebtoken.security.SecurityException | MalformedJwtException e) { - logger.info("잘못된 JWT 서명입니다."); - } catch (ExpiredJwtException e) { - logger.info("만료된 JWT 토큰입니다."); - } catch (UnsupportedJwtException e) { - logger.info("지원되지 않는 JWT 토큰입니다."); - } catch (IllegalArgumentException e) { - logger.info("JWT 토큰이 잘못되었습니다."); - } - return false; - } -} diff --git a/src/main/java/com/hotnerds/badgeroad/login/repository/AuthorityRepository.java b/src/main/java/com/hotnerds/badgeroad/login/repository/AuthorityRepository.java deleted file mode 100644 index b09d8b1..0000000 --- a/src/main/java/com/hotnerds/badgeroad/login/repository/AuthorityRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.hotnerds.badgeroad.login.repository; - -import com.hotnerds.badgeroad.login.entity.Authority; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface AuthorityRepository extends JpaRepository { -} diff --git a/src/main/java/com/hotnerds/badgeroad/login/service/CustomUserDetailsService.java b/src/main/java/com/hotnerds/badgeroad/login/service/CustomUserDetailsService.java deleted file mode 100644 index 3bfcf54..0000000 --- a/src/main/java/com/hotnerds/badgeroad/login/service/CustomUserDetailsService.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.hotnerds.badgeroad.login.service; - -import com.hotnerds.badgeroad.login.entity.User; -import com.hotnerds.badgeroad.login.repository.UserRepository; -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.Component; -import org.springframework.transaction.annotation.Transactional; - -import java.util.List; -import java.util.stream.Collectors; - -@Component("userDetailsService") -public class CustomUserDetailsService implements UserDetailsService { - private final UserRepository userRepository; - - public CustomUserDetailsService(UserRepository userRepository) { - this.userRepository = userRepository; - } - - @Override - @Transactional - public UserDetails loadUserByUsername(final String username) { - return userRepository.findOneWithAuthoritiesByUsername(username) - .map(user -> createUser(username, user)) - .orElseThrow(() -> new UsernameNotFoundException(username + " -> 데이터베이스에서 찾을 수 없습니다.")); - } - - private org.springframework.security.core.userdetails.User createUser(String username, User user) { - if (!user.isActivated()) { - throw new RuntimeException(username + " -> 활성화되어 있지 않습니다."); - } - - List grantedAuthorities = user.getAuthorities().stream() - .map(authority -> new SimpleGrantedAuthority(authority.getAuthorityName())) - .collect(Collectors.toList()); - - return new org.springframework.security.core.userdetails.User(user.getUsername(), - user.getPassword(), - grantedAuthorities); - } -} diff --git a/src/main/java/com/hotnerds/badgeroad/login/service/UserService.java b/src/main/java/com/hotnerds/badgeroad/login/service/UserService.java deleted file mode 100644 index 9dbf11e..0000000 --- a/src/main/java/com/hotnerds/badgeroad/login/service/UserService.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.hotnerds.badgeroad.login.service; - -import com.hotnerds.badgeroad.login.dto.UserDto; -import com.hotnerds.badgeroad.login.entity.Authority; -import com.hotnerds.badgeroad.login.entity.User; -import com.hotnerds.badgeroad.login.exception.DuplicateMemberException; -import com.hotnerds.badgeroad.login.exception.NotFoundMemberException; -import com.hotnerds.badgeroad.login.repository.UserRepository; -import com.hotnerds.badgeroad.login.util.SecurityUtil; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.Collections; - -@Service -public class UserService { - private final UserRepository userRepository; - private final PasswordEncoder passwordEncoder; - - public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) { - this.userRepository = userRepository; - this.passwordEncoder = passwordEncoder; - } - - @Transactional - public UserDto signup(UserDto userDto) { - if (userRepository.findOneWithAuthoritiesByUsername(userDto.getUsername()).orElse(null) != null) { - throw new DuplicateMemberException("이미 가입되어 있는 유저입니다."); - } - - Authority authority = Authority.builder() - .authorityName("ROLE_USER") - .build(); - - User user = User.builder() - .username(userDto.getUsername()) - .password(passwordEncoder.encode(userDto.getPassword())) - .nickname(userDto.getNickname()) - .authorities(Collections.singleton(authority)) - .activated(true) - .build(); - - return UserDto.from(userRepository.save(user)); - } - - @Transactional(readOnly = true) - public UserDto getUserWithAuthorities(String username) { - return UserDto.from(userRepository.findOneWithAuthoritiesByUsername(username).orElse(null)); - } - - @Transactional(readOnly = true) - public UserDto getMyUserWithAuthorities() { - return UserDto.from( - SecurityUtil.getCurrentUsername() - .flatMap(userRepository::findOneWithAuthoritiesByUsername) - .orElseThrow(() -> new NotFoundMemberException("Member not found")) - ); - } -} diff --git a/src/main/java/com/hotnerds/badgeroad/login/controller/UserController.java b/src/main/java/com/hotnerds/badgeroad/user/controller/UserController.java similarity index 56% rename from src/main/java/com/hotnerds/badgeroad/login/controller/UserController.java rename to src/main/java/com/hotnerds/badgeroad/user/controller/UserController.java index 3c3f5d6..04b1021 100644 --- a/src/main/java/com/hotnerds/badgeroad/login/controller/UserController.java +++ b/src/main/java/com/hotnerds/badgeroad/user/controller/UserController.java @@ -1,9 +1,9 @@ -package com.hotnerds.badgeroad.login.controller; +package com.hotnerds.badgeroad.user.controller; -import com.hotnerds.badgeroad.login.dto.UserDto; -import com.hotnerds.badgeroad.login.service.UserService; +import com.hotnerds.badgeroad.user.dto.UserDto; +import com.hotnerds.badgeroad.user.entity.User; +import com.hotnerds.badgeroad.user.service.UserService; import org.springframework.http.ResponseEntity; -import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; @@ -12,7 +12,7 @@ import java.io.IOException; @RestController -@RequestMapping("/api") +@RequestMapping("/user") public class UserController { private final UserService userService; @@ -25,6 +25,11 @@ public String index() { return "index"; } + @GetMapping("/login") + public String login() { + return "login"; + } + @GetMapping("/hello") public ResponseEntity hello() { return ResponseEntity.ok("hello"); @@ -36,21 +41,22 @@ public void testRedirect(HttpServletResponse response) throws IOException { } @PostMapping("/signup") - public ResponseEntity signup( + public String signup( @Valid @RequestBody UserDto userDto ) { - return ResponseEntity.ok(userService.signup(userDto)); + return "redirect:/login"; } - @GetMapping("/user") - @PreAuthorize("hasAnyRole('USER','ADMIN')") - public ResponseEntity getMyUserInfo(HttpServletRequest request) { - return ResponseEntity.ok(userService.getMyUserWithAuthorities()); + @GetMapping("/info") + public String getMyUserInfo(@RequestBody String email) { + UserDto userDto = userService.getUserByEmail(email); + User user = userService.userDtoToUser(userDto); + + return "info"; } - @GetMapping("/user/{username}") - @PreAuthorize("hasAnyRole('ADMIN')") - public ResponseEntity getUserInfo(@PathVariable String username) { - return ResponseEntity.ok(userService.getUserWithAuthorities(username)); + @GetMapping("/user/{email}") + public ResponseEntity getUserInfo(@PathVariable String email) { + return ResponseEntity.ok(userService.getUserByEmail(email)); } } diff --git a/src/main/java/com/hotnerds/badgeroad/login/dto/LoginDto.java b/src/main/java/com/hotnerds/badgeroad/user/dto/LoginDto.java similarity index 88% rename from src/main/java/com/hotnerds/badgeroad/login/dto/LoginDto.java rename to src/main/java/com/hotnerds/badgeroad/user/dto/LoginDto.java index 97b452e..9591511 100644 --- a/src/main/java/com/hotnerds/badgeroad/login/dto/LoginDto.java +++ b/src/main/java/com/hotnerds/badgeroad/user/dto/LoginDto.java @@ -1,4 +1,4 @@ -package com.hotnerds.badgeroad.login.dto; +package com.hotnerds.badgeroad.user.dto; import lombok.*; diff --git a/src/main/java/com/hotnerds/badgeroad/user/dto/SignupDto.java b/src/main/java/com/hotnerds/badgeroad/user/dto/SignupDto.java new file mode 100644 index 0000000..219ea90 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/user/dto/SignupDto.java @@ -0,0 +1,4 @@ +package com.hotnerds.badgeroad.user.dto; + +public class SignupDto { +} diff --git a/src/main/java/com/hotnerds/badgeroad/login/dto/UserDto.java b/src/main/java/com/hotnerds/badgeroad/user/dto/UserDto.java similarity index 55% rename from src/main/java/com/hotnerds/badgeroad/login/dto/UserDto.java rename to src/main/java/com/hotnerds/badgeroad/user/dto/UserDto.java index 66639e5..3d698ed 100644 --- a/src/main/java/com/hotnerds/badgeroad/login/dto/UserDto.java +++ b/src/main/java/com/hotnerds/badgeroad/user/dto/UserDto.java @@ -1,12 +1,12 @@ -package com.hotnerds.badgeroad.login.dto; +package com.hotnerds.badgeroad.user.dto; import com.fasterxml.jackson.annotation.JsonProperty; -import com.hotnerds.badgeroad.login.entity.User; +import com.hotnerds.badgeroad.user.entity.User; import lombok.*; +import javax.persistence.Id; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; -import java.util.Set; import java.util.stream.Collectors; @Getter @@ -18,9 +18,8 @@ public class UserDto { @NotNull @Size(min = 3, max = 50) - private String username; + private String email; - @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) @NotNull @Size(min = 3, max = 100) private String password; @@ -29,17 +28,13 @@ public class UserDto { @Size(min = 3, max = 50) private String nickname; - private Set authorityDtoSet; - public static UserDto from(User user) { if(user == null) return null; return UserDto.builder() - .username(user.getUsername()) + .email(user.getEmail()) + .password(user.getPassword()) .nickname(user.getNickname()) - .authorityDtoSet(user.getAuthorities().stream() - .map(authority -> AuthorityDto.builder().authorityName(authority.getAuthorityName()).build()) - .collect(Collectors.toSet())) .build(); } } \ No newline at end of file diff --git a/src/main/java/com/hotnerds/badgeroad/login/entity/Authority.java b/src/main/java/com/hotnerds/badgeroad/user/entity/Authority.java similarity index 88% rename from src/main/java/com/hotnerds/badgeroad/login/entity/Authority.java rename to src/main/java/com/hotnerds/badgeroad/user/entity/Authority.java index d84e941..63a0114 100644 --- a/src/main/java/com/hotnerds/badgeroad/login/entity/Authority.java +++ b/src/main/java/com/hotnerds/badgeroad/user/entity/Authority.java @@ -1,4 +1,4 @@ -package com.hotnerds.badgeroad.login.entity; +package com.hotnerds.badgeroad.user.entity; import lombok.*; diff --git a/src/main/java/com/hotnerds/badgeroad/user/entity/User.java b/src/main/java/com/hotnerds/badgeroad/user/entity/User.java new file mode 100644 index 0000000..dc2a092 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/user/entity/User.java @@ -0,0 +1,31 @@ +package com.hotnerds.badgeroad.user.entity; + +import lombok.*; + +import javax.persistence.*; +import java.util.Set; + +@Entity +@Table(name = "`user`") +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class User { + + @Id + @Column(name = "user_id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long userId; + + @Column(name = "email", length = 50, unique = true) + private String email; + + @Column(name = "password", length = 100) + private String password; + + @Column(name = "nickname", length = 50) + private String nickname; + +} diff --git a/src/main/java/com/hotnerds/badgeroad/login/exception/DuplicateMemberException.java b/src/main/java/com/hotnerds/badgeroad/user/exception/DuplicateMemberException.java similarity index 89% rename from src/main/java/com/hotnerds/badgeroad/login/exception/DuplicateMemberException.java rename to src/main/java/com/hotnerds/badgeroad/user/exception/DuplicateMemberException.java index 0d6e9c9..26218cc 100644 --- a/src/main/java/com/hotnerds/badgeroad/login/exception/DuplicateMemberException.java +++ b/src/main/java/com/hotnerds/badgeroad/user/exception/DuplicateMemberException.java @@ -1,4 +1,4 @@ -package com.hotnerds.badgeroad.login.exception; +package com.hotnerds.badgeroad.user.exception; public class DuplicateMemberException extends RuntimeException { public DuplicateMemberException() { diff --git a/src/main/java/com/hotnerds/badgeroad/login/exception/NotFoundMemberException.java b/src/main/java/com/hotnerds/badgeroad/user/exception/NotFoundMemberException.java similarity index 89% rename from src/main/java/com/hotnerds/badgeroad/login/exception/NotFoundMemberException.java rename to src/main/java/com/hotnerds/badgeroad/user/exception/NotFoundMemberException.java index 9129846..3d7c0a2 100644 --- a/src/main/java/com/hotnerds/badgeroad/login/exception/NotFoundMemberException.java +++ b/src/main/java/com/hotnerds/badgeroad/user/exception/NotFoundMemberException.java @@ -1,4 +1,4 @@ -package com.hotnerds.badgeroad.login.exception; +package com.hotnerds.badgeroad.user.exception; public class NotFoundMemberException extends RuntimeException { public NotFoundMemberException() { diff --git a/src/main/java/com/hotnerds/badgeroad/login/repository/UserRepository.java b/src/main/java/com/hotnerds/badgeroad/user/repository/UserRepository.java similarity index 61% rename from src/main/java/com/hotnerds/badgeroad/login/repository/UserRepository.java rename to src/main/java/com/hotnerds/badgeroad/user/repository/UserRepository.java index d13828b..e41659c 100644 --- a/src/main/java/com/hotnerds/badgeroad/login/repository/UserRepository.java +++ b/src/main/java/com/hotnerds/badgeroad/user/repository/UserRepository.java @@ -1,6 +1,6 @@ -package com.hotnerds.badgeroad.login.repository; +package com.hotnerds.badgeroad.user.repository; -import com.hotnerds.badgeroad.login.entity.User; +import com.hotnerds.badgeroad.user.entity.User; import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; @@ -8,5 +8,5 @@ public interface UserRepository extends JpaRepository { @EntityGraph(attributePaths = "authorities") - Optional findOneWithAuthoritiesByUsername(String username); + Optional findByEmail(String email); } diff --git a/src/main/java/com/hotnerds/badgeroad/user/service/UserService.java b/src/main/java/com/hotnerds/badgeroad/user/service/UserService.java new file mode 100644 index 0000000..9c728f2 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/user/service/UserService.java @@ -0,0 +1,44 @@ +package com.hotnerds.badgeroad.user.service; + +import com.hotnerds.badgeroad.user.dto.UserDto; +import com.hotnerds.badgeroad.user.entity.User; +import com.hotnerds.badgeroad.user.exception.DuplicateMemberException; +import com.hotnerds.badgeroad.user.repository.UserRepository; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + + +@Service +@AllArgsConstructor +public class UserService { + private final UserRepository userRepository; + + @Transactional + public UserDto signup(UserDto userDto) { + if (userRepository.findByEmail(userDto.getEmail()).orElse(null) != null) { + throw new DuplicateMemberException("이미 가입되어 있는 유저입니다."); + } + + User user = User.builder() + .email(userDto.getEmail()) + .password(userDto.getPassword()) + .nickname(userDto.getNickname()) + .build(); + + return UserDto.from(userRepository.save(user)); + } + + @Transactional + public UserDto getUserByEmail(String email) { + return UserDto.from(userRepository.findByEmail(email).orElse(null)); + } + + public User userDtoToUser(UserDto userDto) { + return User.builder() + .email(userDto.getEmail()) + .password(userDto.getPassword()) + .nickname(userDto.getNickname()) + .build(); + } +} diff --git a/src/main/java/com/hotnerds/badgeroad/login/util/SecurityUtil.java b/src/main/java/com/hotnerds/badgeroad/user/util/SecurityUtil.java similarity index 96% rename from src/main/java/com/hotnerds/badgeroad/login/util/SecurityUtil.java rename to src/main/java/com/hotnerds/badgeroad/user/util/SecurityUtil.java index 669f663..de00cf0 100644 --- a/src/main/java/com/hotnerds/badgeroad/login/util/SecurityUtil.java +++ b/src/main/java/com/hotnerds/badgeroad/user/util/SecurityUtil.java @@ -1,4 +1,4 @@ -package com.hotnerds.badgeroad.login.util; +package com.hotnerds.badgeroad.user.util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/resources/templates/common.html b/src/main/resources/templates/common.html new file mode 100644 index 0000000..f72ff04 --- /dev/null +++ b/src/main/resources/templates/common.html @@ -0,0 +1,35 @@ + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html new file mode 100644 index 0000000..b7983cf --- /dev/null +++ b/src/main/resources/templates/index.html @@ -0,0 +1,12 @@ + + + + + + +

HOME

+

LOGIN

+

SIGNUP

+ + + \ No newline at end of file diff --git a/src/main/resources/templates/login.html b/src/main/resources/templates/login.html new file mode 100644 index 0000000..b2ce4f9 --- /dev/null +++ b/src/main/resources/templates/login.html @@ -0,0 +1,102 @@ + + + + + + + LOGIN + + +

HOME

+

LOGIN

+

SIGNUP

+ +
+
+ + +
+
+ + +
+
+ + Not registered? + Register/SignUp Here + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/members.html b/src/main/resources/templates/members.html new file mode 100644 index 0000000..fa4ccce --- /dev/null +++ b/src/main/resources/templates/members.html @@ -0,0 +1,54 @@ + + + + + Registration and Login System + + + + +
+
+

Registered Users

+
+ + + + + + + + + + + + + + + +
First NameLast NameEmail
+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/signup.html b/src/main/resources/templates/signup.html new file mode 100644 index 0000000..f071edd --- /dev/null +++ b/src/main/resources/templates/signup.html @@ -0,0 +1,74 @@ + + + + + + + + +

HOME

+

LOGIN

+

SIGNUP

+ +
+
+
+
+
You've successfully registered + to our app!
+
+
+

Registration

+
+
+
+ +
+ + +
+
+ + +

+

+
+
+ + +

+

+
+ +
+ + Already registered? Login + here +
+
+
+
+
+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/user_access.html b/src/main/resources/templates/user_access.html new file mode 100644 index 0000000..d64f584 --- /dev/null +++ b/src/main/resources/templates/user_access.html @@ -0,0 +1,13 @@ + + + + + + + user access + + +환영합니다 +

+ + \ No newline at end of file diff --git a/src/main/resources/trash/config/SecurityConfig.java b/src/main/resources/trash/config/SecurityConfig.java new file mode 100644 index 0000000..06f46a6 --- /dev/null +++ b/src/main/resources/trash/config/SecurityConfig.java @@ -0,0 +1,98 @@ +package com.hotnerds.badgeroad.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +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.annotation.web.configurers.LogoutConfigurer; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +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 +@EnableGlobalMethodSecurity( + securedEnabled = true, + jsr250Enabled = true, + prePostEnabled = true +) +public class SecurityConfig{ + +// private final ObjectMapper objectMapper; + @Autowired + private UserDetailsService userDetailsService; + + private static final String[] AUTH_WHITELIST = { + "open/**" + }; + + @Bean + public static PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Bean + public WebSecurityCustomizer configure() { + return web -> web.ignoring().mvcMatchers(AUTH_WHITELIST); + } + + @Bean + public AuthenticationManager authenticationManagerBean() throws Exception { + return new AuthenticationManager() { + @Override + public Authentication authenticate(Authentication authentication) throws AuthenticationException { + return null; + } + }; + } + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http.csrf().disable() + .authorizeRequests() + .antMatchers("/signup/**").permitAll() + .antMatchers("/index").permitAll() + .antMatchers("/members").hasRole("ADMIN") + .and(). + formLogin( + form -> form + .loginPage("/login") + .loginProcessingUrl("/login") + .defaultSuccessUrl("/members") + .permitAll() + ).logout( + logout -> logout + .logoutRequestMatcher(new AntPathRequestMatcher("/logout")) + .permitAll() + ); + return http.build(); + } + + @Autowired + public void configure(AuthenticationManagerBuilder auth) throws Exception { + auth + .userDetailsService(userDetailsService) + .passwordEncoder(passwordEncoder()); + } + +// @Bean +// public UserDetailsService userDetailsService() { +// UserDetails user = +// User.withUserDetails() +// .username("user") +// .password("password") +// .roles("USER") +// .build(); +// +// return new InMemoryUserDetailsManager(user); +// } +} diff --git a/src/main/resources/trash/controller/AuthController.java b/src/main/resources/trash/controller/AuthController.java new file mode 100644 index 0000000..95bf4cf --- /dev/null +++ b/src/main/resources/trash/controller/AuthController.java @@ -0,0 +1,77 @@ +package com.hotnerds.badgeroad.controller; + +import com.hotnerds.badgeroad.dto.MemberDto; +import com.hotnerds.badgeroad.entity.Member; +import com.hotnerds.badgeroad.service.MemberService; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; + +@Controller +public class AuthController { + private final MemberService memberService; + + public AuthController(MemberService memberService) { + this.memberService = memberService; + } + + @GetMapping("index") + public String homepage(){ + return "index"; + } + + @GetMapping("/login") + public String loginForm() { + return "login"; + } + + @GetMapping("/signup") + public String showRegistrationForm(Model model){ + MemberDto member = new MemberDto(); + model.addAttribute("member", member); + return "signup"; + } + + @GetMapping("/common") + public String common() { + return "common"; + } + + +// +// @PostMapping("/login") +// public String loginConfirm() { +// return "login"; +// } + + // handler method to handle Member registration request + + + // handler method to handle register Member form submit request + @PostMapping("/signup") + public String registration(@Valid @ModelAttribute("Member") MemberDto member, + BindingResult result, + Model model){ + Member existing = memberService.findByEmail(member.getEmail()); + if (existing != null) { + result.rejectValue("email", null, "There is already an account registered with that email"); + } + if (result.hasErrors()) { + model.addAttribute("member", member); + return "signup"; + } + memberService.saveMember(member); + return "redirect:/login"; + } + + @GetMapping("/members") + public String listRegisteredMembers(Model model){ + List members = memberService.findAllMembers(); + model.addAttribute("Members", members); + return "members"; + } +} diff --git a/src/main/resources/trash/controller/HomeController.java b/src/main/resources/trash/controller/HomeController.java new file mode 100644 index 0000000..02b9652 --- /dev/null +++ b/src/main/resources/trash/controller/HomeController.java @@ -0,0 +1,8 @@ +package com.hotnerds.badgeroad.controller; + +import com.hotnerds.badgeroad.dto.MemberDto; + +public class HomeController { + + +} diff --git a/src/main/resources/trash/dto/MemberDto.java b/src/main/resources/trash/dto/MemberDto.java new file mode 100644 index 0000000..c691632 --- /dev/null +++ b/src/main/resources/trash/dto/MemberDto.java @@ -0,0 +1,25 @@ +package com.hotnerds.badgeroad.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import javax.validation.constraints.Email; +import javax.validation.constraints.NotEmpty; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class MemberDto +{ + private Long id; + @NotEmpty(message = "Email should not be empty") + @Email + private String email; + @NotEmpty(message = "Password should not be empty") + private String password; + @NotEmpty(message = "name should not be empty") + private String name; +} \ No newline at end of file diff --git a/src/main/resources/trash/dto/MemberSignupRequestDto.java b/src/main/resources/trash/dto/MemberSignupRequestDto.java new file mode 100644 index 0000000..99bbd4a --- /dev/null +++ b/src/main/resources/trash/dto/MemberSignupRequestDto.java @@ -0,0 +1,12 @@ +package com.hotnerds.badgeroad.dto; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class MemberSignupRequestDto { + private String email; + private String password; + private String name; +} diff --git a/src/main/resources/trash/entity/Member.java b/src/main/resources/trash/entity/Member.java new file mode 100644 index 0000000..cea5771 --- /dev/null +++ b/src/main/resources/trash/entity/Member.java @@ -0,0 +1,41 @@ +package com.hotnerds.badgeroad.entity; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import javax.persistence.*; +import java.util.ArrayList; +import java.util.List; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "member") +public class Member { + + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable=false) + private String name; + + @Column(nullable=false, unique=true) + private String email; + + @Column(nullable=false) + private String password; + + @ManyToMany(fetch = FetchType.EAGER, cascade=CascadeType.ALL) + @JoinTable( + name="member_role", + joinColumns={@JoinColumn(name="MEMBER_ID", referencedColumnName="ID")}, + inverseJoinColumns={@JoinColumn(name="ROLE_ID", referencedColumnName="ID")}) + private List roles = new ArrayList<>(); +} diff --git a/src/main/resources/trash/entity/Role.java b/src/main/resources/trash/entity/Role.java new file mode 100644 index 0000000..fe4cbb4 --- /dev/null +++ b/src/main/resources/trash/entity/Role.java @@ -0,0 +1,28 @@ +package com.hotnerds.badgeroad.entity; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import javax.persistence.*; +import java.util.List; + +@Setter +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name="role") +public class Role +{ + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable=false, unique=true) + private String name; + + @ManyToMany(mappedBy="roles") + private List members; +} diff --git a/src/main/resources/trash/login.html b/src/main/resources/trash/login.html new file mode 100644 index 0000000..c1e4ea9 --- /dev/null +++ b/src/main/resources/trash/login.html @@ -0,0 +1,76 @@ + + + + + Registration and Login System + + + + +
+
+
+
+
+
+
+
Invalid Email and Password.
+
+
+
You have been logged out.
+
+
+
+

Login Form

+
+
+
+
+ + +
+ +
+ + +
+ +
+ + Not registered? + Register/SignUp Here + +
+
+
+
+
+
+
+ + \ No newline at end of file diff --git a/src/main/resources/trash/repository/MemberRepository.java b/src/main/resources/trash/repository/MemberRepository.java new file mode 100644 index 0000000..26a3d92 --- /dev/null +++ b/src/main/resources/trash/repository/MemberRepository.java @@ -0,0 +1,9 @@ +package com.hotnerds.badgeroad.repository; + +import com.hotnerds.badgeroad.entity.Member; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface MemberRepository extends JpaRepository { + + Member findByEmail(String email); +} diff --git a/src/main/resources/trash/repository/RoleRepository.java b/src/main/resources/trash/repository/RoleRepository.java new file mode 100644 index 0000000..cbbf01a --- /dev/null +++ b/src/main/resources/trash/repository/RoleRepository.java @@ -0,0 +1,8 @@ +package com.hotnerds.badgeroad.repository; + +import com.hotnerds.badgeroad.entity.Role; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface RoleRepository extends JpaRepository { + Role findByName(String name); +} diff --git a/src/main/resources/trash/service/CustomUserDetailsService.java b/src/main/resources/trash/service/CustomUserDetailsService.java new file mode 100644 index 0000000..535f189 --- /dev/null +++ b/src/main/resources/trash/service/CustomUserDetailsService.java @@ -0,0 +1,43 @@ +package com.hotnerds.badgeroad.service; + +import com.hotnerds.badgeroad.entity.Member; +import com.hotnerds.badgeroad.entity.Role; +import com.hotnerds.badgeroad.repository.MemberRepository; +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 java.util.Collection; +import java.util.stream.Collectors; + +@Service +public class CustomUserDetailsService implements UserDetailsService { + private final MemberRepository memberRepository; + + public CustomUserDetailsService(MemberRepository MemberRepository) { + this.memberRepository = MemberRepository; + } + + @Override + public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { + Member member = memberRepository.findByEmail(email); + + if (member != null) { + return new org.springframework.security.core.userdetails.User(member.getEmail(), + member.getPassword(), + mapRolesToAuthorities(member.getRoles())); + }else{ + throw new UsernameNotFoundException("Invalid username or password."); + } + } + + private Collection< ? extends GrantedAuthority> mapRolesToAuthorities(Collection roles) { + Collection < ? extends GrantedAuthority> mapRoles = roles.stream() + .map(role -> new SimpleGrantedAuthority(role.getName())) + .collect(Collectors.toList()); + return mapRoles; + } +} diff --git a/src/main/resources/trash/service/MemberService.java b/src/main/resources/trash/service/MemberService.java new file mode 100644 index 0000000..9c80395 --- /dev/null +++ b/src/main/resources/trash/service/MemberService.java @@ -0,0 +1,14 @@ +package com.hotnerds.badgeroad.service; + +import com.hotnerds.badgeroad.dto.MemberDto; +import com.hotnerds.badgeroad.entity.Member; + +import java.util.List; + +public interface MemberService { + void saveMember(MemberDto memberDto); + + Member findByEmail(String email); + + List findAllMembers(); +} \ No newline at end of file diff --git a/src/main/resources/trash/service/MemberServiceImpl.java b/src/main/resources/trash/service/MemberServiceImpl.java new file mode 100644 index 0000000..6a0287e --- /dev/null +++ b/src/main/resources/trash/service/MemberServiceImpl.java @@ -0,0 +1,72 @@ +package com.hotnerds.badgeroad.service; + +import com.hotnerds.badgeroad.dto.MemberDto; +import com.hotnerds.badgeroad.entity.Member; +import com.hotnerds.badgeroad.entity.Role; +import com.hotnerds.badgeroad.repository.MemberRepository; +import com.hotnerds.badgeroad.repository.RoleRepository; +import lombok.AllArgsConstructor; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +@AllArgsConstructor +public class MemberServiceImpl implements MemberService { + + private MemberRepository MemberRepository; + private RoleRepository roleRepository; + private PasswordEncoder passwordEncoder; + +// public MemberServiceImpl(MemberRepository MemberRepository, +// RoleRepository roleRepository, +// PasswordEncoder passwordEncoder) { +// this.MemberRepository = MemberRepository; +// this.roleRepository = roleRepository; +// this.passwordEncoder = passwordEncoder; +// } + + @Override + public void saveMember(MemberDto MemberDto) { + Member member = new Member(); + member.setName(MemberDto.getName()); + member.setEmail(MemberDto.getEmail()); + + //encrypt the password once we integrate spring security + //Member.setPassword(MemberDto.getPassword()); + member.setPassword(passwordEncoder.encode(MemberDto.getPassword())); + Role role = roleRepository.findByName("ROLE_ADMIN"); + if (role == null) { + role = checkRoleExist(); + } + member.setRoles(List.of(role)); + MemberRepository.save(member); + } + + @Override + public Member findByEmail(String email) { + return MemberRepository.findByEmail(email); + } + + @Override + public List findAllMembers() { + List members = MemberRepository.findAll(); + return members.stream().map(this::convertEntityToDto) + .collect(Collectors.toList()); + } + + private MemberDto convertEntityToDto(Member member) { + MemberDto memberDto = new MemberDto(); + memberDto.setName(member.getName()); + memberDto.setEmail(member.getEmail()); + return memberDto; + } + + private Role checkRoleExist() { + Role role = new Role(); + role.setName("ROLE_ADMIN"); + return roleRepository.save(role); + } +} \ No newline at end of file diff --git a/src/main/resources/trash/yamlreadDB/ApplicationDBRead.java b/src/main/resources/trash/yamlreadDB/ApplicationDBRead.java new file mode 100644 index 0000000..e71bfaf --- /dev/null +++ b/src/main/resources/trash/yamlreadDB/ApplicationDBRead.java @@ -0,0 +1,18 @@ +package com.hotnerds.badgeroad.yamlreadDB; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; + +@Configuration +//value를 통해 값이 있는 위치를 명시해준다. +@PropertySource(value = "classpath:application.yml", factory = YamlPropertySourceFactory.class) +// yml 파일에서 가져올 변수 이름을 명시해준다. +@ConfigurationProperties(prefix = "spring.datasource") +@Setter +@Getter +public class ApplicationDBRead { + private DBSource dbSource; +} \ No newline at end of file diff --git a/src/main/resources/trash/yamlreadDB/DBSource.java b/src/main/resources/trash/yamlreadDB/DBSource.java new file mode 100644 index 0000000..c48f8cb --- /dev/null +++ b/src/main/resources/trash/yamlreadDB/DBSource.java @@ -0,0 +1,17 @@ +package com.hotnerds.badgeroad.yamlreadDB; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class DBSource { + private String driver; + private String url; + private String username; + private String password; +} diff --git a/src/main/resources/trash/yamlreadDB/YamlPropertySourceFactory.java b/src/main/resources/trash/yamlreadDB/YamlPropertySourceFactory.java new file mode 100644 index 0000000..ab51009 --- /dev/null +++ b/src/main/resources/trash/yamlreadDB/YamlPropertySourceFactory.java @@ -0,0 +1,37 @@ +package com.hotnerds.badgeroad.yamlreadDB; + +import org.springframework.beans.factory.config.YamlPropertiesFactoryBean; +import org.springframework.core.env.PropertiesPropertySource; +import org.springframework.core.env.PropertySource; +import org.springframework.core.io.support.EncodedResource; +import org.springframework.core.io.support.PropertySourceFactory; +import org.springframework.lang.Nullable; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Properties; + +public class YamlPropertySourceFactory implements PropertySourceFactory { + + @Override + public PropertySource createPropertySource(@Nullable String name, EncodedResource resource) throws IOException { + Properties propertiesFromYaml = loadYamlIntoProperties(resource); + String sourceName = name != null ? name : resource.getResource().getFilename(); + return new PropertiesPropertySource(sourceName, propertiesFromYaml); + } + + private Properties loadYamlIntoProperties(EncodedResource resource) throws FileNotFoundException { + try { + YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean(); + factory.setResources(resource.getResource()); + factory.afterPropertiesSet(); + return factory.getObject(); + } catch (IllegalStateException e) { + // for ignoreResourceNotFound + Throwable cause = e.getCause(); + if (cause instanceof FileNotFoundException) + throw (FileNotFoundException) e.getCause(); + throw e; + } + } +} From 83b1a29e9e5f302ef0fd8c56642adb2ec1a58767 Mon Sep 17 00:00:00 2001 From: "Shin, Jeongbin" Date: Thu, 15 Dec 2022 14:16:26 +0900 Subject: [PATCH 04/11] init --- pom.xml | 20 ---- .../hotnerds/badgeroad/HomeController.java | 22 ----- .../badgeroad/home/HomeController.java | 7 +- .../user/controller/LoginController.java | 75 -------------- .../user/controller/UserController.java | 65 ++++++++---- .../hotnerds/badgeroad/user/dto/LoginDto.java | 2 +- .../user/dto/MemberSignupRequestDto.java | 12 --- .../badgeroad/user/dto/SignupDto.java | 21 ++++ .../badgeroad/user/entity/Authority.java | 22 ----- .../badgeroad/user/entity/Member.java | 41 -------- .../hotnerds/badgeroad/user/entity/Role.java | 3 - .../user/repository/MemberRepository.java | 9 -- .../user/repository/UserRepository.java | 1 - .../badgeroad/user/service/MemberService.java | 17 ---- .../user/service/MemberServiceImpl.java | 77 --------------- .../badgeroad/user/service/UserService.java | 19 +++- .../badgeroad/user/util/SecurityUtil.java | 35 ------- src/main/resources/application-api.yml | 0 src/main/resources/application.yml | 4 +- src/main/resources/data.sql | 16 +-- .../templates/login/config/CorsConfig.java | 23 ----- .../login/config/SecurityConfig.java | 89 ----------------- .../login/controller/AuthController.java | 58 ----------- .../login/controller/UserController.java | 56 ----------- .../templates/login/dto/AuthorityDto.java | 12 --- .../templates/login/dto/ErrorDto.java | 34 ------- .../templates/login/dto/LoginDto.java | 22 ----- .../templates/login/dto/TokenDto.java | 13 --- .../templates/login/dto/UserDto.java | 45 --------- .../templates/login/entity/Authority.java | 22 ----- .../templates/login/entity/User.java | 40 -------- .../exception/DuplicateMemberException.java | 16 --- .../exception/NotFoundMemberException.java | 16 --- ...ethodArgumentNotValidExceptionHandler.java | 37 ------- .../handler/RestResponseExceptionHandler.java | 33 ------- .../login/jwt/JwtAccessDeniedHandler.java | 18 ---- .../jwt/JwtAuthenticationEntryPoint.java | 20 ---- .../templates/login/jwt/JwtFilter.java | 52 ---------- .../login/jwt/JwtSecurityConfig.java | 21 ---- .../templates/login/jwt/TokenProvider.java | 94 ------------------ .../login/repository/AuthorityRepository.java | 7 -- .../login/repository/UserRepository.java | 12 --- .../service/CustomUserDetailsService.java | 45 --------- .../templates/login/service/UserService.java | 60 ------------ .../templates/login/util/SecurityUtil.java | 35 ------- src/main/resources/templates/main.html | 2 +- .../trash/config/SecurityConfig.java | 98 ------------------- .../trash/controller/AuthController.java | 77 --------------- .../trash/controller/HomeController.java | 8 -- src/main/resources/trash/dto/MemberDto.java | 25 ----- .../trash/dto/MemberSignupRequestDto.java | 12 --- src/main/resources/trash/entity/Member.java | 41 -------- src/main/resources/trash/entity/Role.java | 28 ------ src/main/resources/trash/login.html | 76 -------------- .../trash/repository/MemberRepository.java | 9 -- .../trash/repository/RoleRepository.java | 8 -- .../service/CustomUserDetailsService.java | 43 -------- .../trash/service/MemberService.java | 14 --- .../trash/service/MemberServiceImpl.java | 72 -------------- .../trash/yamlreadDB/ApplicationDBRead.java | 18 ---- .../resources/trash/yamlreadDB/DBSource.java | 17 ---- .../yamlreadDB/YamlPropertySourceFactory.java | 37 ------- 62 files changed, 100 insertions(+), 1833 deletions(-) delete mode 100644 src/main/java/com/hotnerds/badgeroad/HomeController.java delete mode 100644 src/main/java/com/hotnerds/badgeroad/user/controller/LoginController.java delete mode 100644 src/main/java/com/hotnerds/badgeroad/user/dto/MemberSignupRequestDto.java delete mode 100644 src/main/java/com/hotnerds/badgeroad/user/entity/Authority.java delete mode 100644 src/main/java/com/hotnerds/badgeroad/user/entity/Member.java delete mode 100644 src/main/java/com/hotnerds/badgeroad/user/repository/MemberRepository.java delete mode 100644 src/main/java/com/hotnerds/badgeroad/user/service/MemberService.java delete mode 100644 src/main/java/com/hotnerds/badgeroad/user/service/MemberServiceImpl.java delete mode 100644 src/main/java/com/hotnerds/badgeroad/user/util/SecurityUtil.java delete mode 100644 src/main/resources/application-api.yml delete mode 100644 src/main/resources/templates/login/config/CorsConfig.java delete mode 100644 src/main/resources/templates/login/config/SecurityConfig.java delete mode 100644 src/main/resources/templates/login/controller/AuthController.java delete mode 100644 src/main/resources/templates/login/controller/UserController.java delete mode 100644 src/main/resources/templates/login/dto/AuthorityDto.java delete mode 100644 src/main/resources/templates/login/dto/ErrorDto.java delete mode 100644 src/main/resources/templates/login/dto/LoginDto.java delete mode 100644 src/main/resources/templates/login/dto/TokenDto.java delete mode 100644 src/main/resources/templates/login/dto/UserDto.java delete mode 100644 src/main/resources/templates/login/entity/Authority.java delete mode 100644 src/main/resources/templates/login/entity/User.java delete mode 100644 src/main/resources/templates/login/exception/DuplicateMemberException.java delete mode 100644 src/main/resources/templates/login/exception/NotFoundMemberException.java delete mode 100644 src/main/resources/templates/login/handler/MethodArgumentNotValidExceptionHandler.java delete mode 100644 src/main/resources/templates/login/handler/RestResponseExceptionHandler.java delete mode 100644 src/main/resources/templates/login/jwt/JwtAccessDeniedHandler.java delete mode 100644 src/main/resources/templates/login/jwt/JwtAuthenticationEntryPoint.java delete mode 100644 src/main/resources/templates/login/jwt/JwtFilter.java delete mode 100644 src/main/resources/templates/login/jwt/JwtSecurityConfig.java delete mode 100644 src/main/resources/templates/login/jwt/TokenProvider.java delete mode 100644 src/main/resources/templates/login/repository/AuthorityRepository.java delete mode 100644 src/main/resources/templates/login/repository/UserRepository.java delete mode 100644 src/main/resources/templates/login/service/CustomUserDetailsService.java delete mode 100644 src/main/resources/templates/login/service/UserService.java delete mode 100644 src/main/resources/templates/login/util/SecurityUtil.java delete mode 100644 src/main/resources/trash/config/SecurityConfig.java delete mode 100644 src/main/resources/trash/controller/AuthController.java delete mode 100644 src/main/resources/trash/controller/HomeController.java delete mode 100644 src/main/resources/trash/dto/MemberDto.java delete mode 100644 src/main/resources/trash/dto/MemberSignupRequestDto.java delete mode 100644 src/main/resources/trash/entity/Member.java delete mode 100644 src/main/resources/trash/entity/Role.java delete mode 100644 src/main/resources/trash/login.html delete mode 100644 src/main/resources/trash/repository/MemberRepository.java delete mode 100644 src/main/resources/trash/repository/RoleRepository.java delete mode 100644 src/main/resources/trash/service/CustomUserDetailsService.java delete mode 100644 src/main/resources/trash/service/MemberService.java delete mode 100644 src/main/resources/trash/service/MemberServiceImpl.java delete mode 100644 src/main/resources/trash/yamlreadDB/ApplicationDBRead.java delete mode 100644 src/main/resources/trash/yamlreadDB/DBSource.java delete mode 100644 src/main/resources/trash/yamlreadDB/YamlPropertySourceFactory.java diff --git a/pom.xml b/pom.xml index 33fc729..18595e4 100644 --- a/pom.xml +++ b/pom.xml @@ -51,8 +51,6 @@ spring-boot-starter-test test -<<<<<<< Updated upstream -======= com.googlecode.json-simple json-simple @@ -67,24 +65,6 @@ spring-boot-configuration-processor true - - io.jsonwebtoken - jjwt-api - 0.11.5 - - - io.jsonwebtoken - jjwt-impl - 0.11.5 - runtime - - - io.jsonwebtoken - jjwt-jackson - 0.11.5 - runtime - ->>>>>>> Stashed changes diff --git a/src/main/java/com/hotnerds/badgeroad/HomeController.java b/src/main/java/com/hotnerds/badgeroad/HomeController.java deleted file mode 100644 index 7a62c65..0000000 --- a/src/main/java/com/hotnerds/badgeroad/HomeController.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.hotnerds.badgeroad; - -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -public class HomeController { - @GetMapping("/") - public String home() { - return "hello"; - } - - @GetMapping("dashboard") - public String dashboard() { - return "dashboard"; - } - - @GetMapping("admin") - public String admin() { - return "admin"; - } -} \ No newline at end of file diff --git a/src/main/java/com/hotnerds/badgeroad/home/HomeController.java b/src/main/java/com/hotnerds/badgeroad/home/HomeController.java index 119eb29..6db51b9 100644 --- a/src/main/java/com/hotnerds/badgeroad/home/HomeController.java +++ b/src/main/java/com/hotnerds/badgeroad/home/HomeController.java @@ -6,8 +6,13 @@ @Controller public class HomeController { - @GetMapping("index") + @GetMapping("/") public String homepage() { return "index"; } + + @GetMapping("/user") + public String user() { + return "login"; + } } diff --git a/src/main/java/com/hotnerds/badgeroad/user/controller/LoginController.java b/src/main/java/com/hotnerds/badgeroad/user/controller/LoginController.java deleted file mode 100644 index 5b5bb14..0000000 --- a/src/main/java/com/hotnerds/badgeroad/user/controller/LoginController.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.hotnerds.badgeroad.user.controller; - -import com.hotnerds.badgeroad.user.dto.MemberDto; -import com.hotnerds.badgeroad.user.entity.Member; -import com.hotnerds.badgeroad.user.service.MemberService; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.validation.BindingResult; -import org.springframework.web.bind.annotation.*; - -import javax.validation.Valid; -import java.util.List; - -@Controller -@RequestMapping("/user") -public class LoginController { - private final MemberService memberService; - - public LoginController(MemberService memberService) { - this.memberService = memberService; - } - - @GetMapping("/login") - public String loginForm() { - return "login"; - } - - @GetMapping("/signup") - public String showRegistrationForm(Model model){ - MemberDto member = new MemberDto(); - model.addAttribute("member", member); - return "signup"; - } - - @GetMapping("/common") - public String common() { - return "common"; - } - - - - @PostMapping("/login") - public String loginConfirm(@ModelAttribute("Member") MemberDto member, - BindingResult result, - Model model) { - return "redirect:/main"; - } - - // handler method to handle Member registration request - - - // handler method to handle register Member form submit request - @PostMapping("/signup") - public String registration(@Valid @ModelAttribute("Member") MemberDto member, - BindingResult result, - Model model){ - Member existing = memberService.findByEmail(member.getEmail()); - if (existing != null) { - result.rejectValue("email", null, "There is already an account registered with that email"); - } - if (result.hasErrors()) { - model.addAttribute("member", member); - return "signup"; - } - memberService.saveMember(member); - return "good"; - } - - @GetMapping("/members") - public String listRegisteredMembers(Model model){ - List members = memberService.findAllMembers(); - model.addAttribute("Members", members); - return "members"; - } -} diff --git a/src/main/java/com/hotnerds/badgeroad/user/controller/UserController.java b/src/main/java/com/hotnerds/badgeroad/user/controller/UserController.java index 04b1021..d4843af 100644 --- a/src/main/java/com/hotnerds/badgeroad/user/controller/UserController.java +++ b/src/main/java/com/hotnerds/badgeroad/user/controller/UserController.java @@ -1,15 +1,20 @@ package com.hotnerds.badgeroad.user.controller; +import com.hotnerds.badgeroad.user.dto.LoginDto; +import com.hotnerds.badgeroad.user.dto.MemberDto; import com.hotnerds.badgeroad.user.dto.UserDto; import com.hotnerds.badgeroad.user.entity.User; import com.hotnerds.badgeroad.user.service.UserService; import org.springframework.http.ResponseEntity; +import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; import java.io.IOException; +import java.util.List; @RestController @RequestMapping("/user") @@ -20,43 +25,61 @@ public UserController(UserService userService) { this.userService = userService; } - @GetMapping("/") - public String index() { - return "index"; - } - @GetMapping("/login") public String login() { return "login"; } + @PostMapping("/login") + public String loginConfirm(@Valid @RequestBody LoginDto loginDto) { + userService.loginConfirm(loginDto); + + return "main"; + } + @GetMapping("/hello") public ResponseEntity hello() { return ResponseEntity.ok("hello"); } - @PostMapping("/test-redirect") - public void testRedirect(HttpServletResponse response) throws IOException { - response.sendRedirect("/api/user"); + @GetMapping("/{email}") + public ResponseEntity getUserInfo(@PathVariable String email) { + return ResponseEntity.ok(userService.findByEmail(email)); } - @PostMapping("/signup") - public String signup( - @Valid @RequestBody UserDto userDto - ) { - return "redirect:/login"; + @GetMapping("/signup") + public String showRegistrationForm(Model model){ + MemberDto member = new MemberDto(); + model.addAttribute("member", member); + return "signup"; } - @GetMapping("/info") - public String getMyUserInfo(@RequestBody String email) { - UserDto userDto = userService.getUserByEmail(email); - User user = userService.userDtoToUser(userDto); - return "info"; + + // handler method to handle Member registration request + + + // handler method to handle register Member form submit request + @PostMapping("/signup") + public String registration(@Valid @ModelAttribute("user") UserDto user, + BindingResult result, + Model model){ + UserDto existing = userService.findByEmail(user.getEmail()); + if (existing != null) { + result.rejectValue("email", null, "There is already an account registered with that email"); + } + if (result.hasErrors()) { + model.addAttribute("user", user); + return "signup"; + } + userService.saveUser(userService.userDtoToUser(user)); + return "redirect:/login"; } - @GetMapping("/user/{email}") - public ResponseEntity getUserInfo(@PathVariable String email) { - return ResponseEntity.ok(userService.getUserByEmail(email)); + @GetMapping("/users") + public String listRegisteredMembers(Model model){ + List users = userService.findAllUsers(); + model.addAttribute("Users", users); + return "users"; } } diff --git a/src/main/java/com/hotnerds/badgeroad/user/dto/LoginDto.java b/src/main/java/com/hotnerds/badgeroad/user/dto/LoginDto.java index 9591511..c2aabeb 100644 --- a/src/main/java/com/hotnerds/badgeroad/user/dto/LoginDto.java +++ b/src/main/java/com/hotnerds/badgeroad/user/dto/LoginDto.java @@ -14,7 +14,7 @@ public class LoginDto { @NotNull @Size(min = 3, max = 50) - private String username; + private String email; @NotNull @Size(min = 3, max = 100) diff --git a/src/main/java/com/hotnerds/badgeroad/user/dto/MemberSignupRequestDto.java b/src/main/java/com/hotnerds/badgeroad/user/dto/MemberSignupRequestDto.java deleted file mode 100644 index 5ea3d23..0000000 --- a/src/main/java/com/hotnerds/badgeroad/user/dto/MemberSignupRequestDto.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.hotnerds.badgeroad.user.dto; - -import lombok.Getter; -import lombok.Setter; - -@Getter -@Setter -public class MemberSignupRequestDto { - private String email; - private String password; - private String name; -} diff --git a/src/main/java/com/hotnerds/badgeroad/user/dto/SignupDto.java b/src/main/java/com/hotnerds/badgeroad/user/dto/SignupDto.java index 219ea90..7b3097a 100644 --- a/src/main/java/com/hotnerds/badgeroad/user/dto/SignupDto.java +++ b/src/main/java/com/hotnerds/badgeroad/user/dto/SignupDto.java @@ -1,4 +1,25 @@ package com.hotnerds.badgeroad.user.dto; + +import lombok.Getter; +import lombok.Setter; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +@Getter +@Setter public class SignupDto { + + @NotNull + @Size(min = 3, max = 50) + private String email; + + @NotNull + @Size(min = 3, max = 100) + private String password; + + @NotNull + @Size(min = 3, max = 50) + private String nickname; } diff --git a/src/main/java/com/hotnerds/badgeroad/user/entity/Authority.java b/src/main/java/com/hotnerds/badgeroad/user/entity/Authority.java deleted file mode 100644 index 63a0114..0000000 --- a/src/main/java/com/hotnerds/badgeroad/user/entity/Authority.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.hotnerds.badgeroad.user.entity; - -import lombok.*; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Table; - -@Entity -@Table(name = "authority") -@Getter -@Setter -@Builder -@AllArgsConstructor -@NoArgsConstructor -public class Authority { - - @Id - @Column(name = "authority_name", length = 50) - private String authorityName; -} diff --git a/src/main/java/com/hotnerds/badgeroad/user/entity/Member.java b/src/main/java/com/hotnerds/badgeroad/user/entity/Member.java deleted file mode 100644 index 4887436..0000000 --- a/src/main/java/com/hotnerds/badgeroad/user/entity/Member.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.hotnerds.badgeroad.user.entity; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import javax.persistence.*; -import java.util.ArrayList; -import java.util.List; - -@Getter -@Setter -@NoArgsConstructor -@AllArgsConstructor -@Entity -@Table(name = "member") -public class Member { - - private static final long serialVersionUID = 1L; - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @Column(nullable=false) - private String name; - - @Column(nullable=false, unique=true) - private String email; - - @Column(nullable=false) - private String password; - - @ManyToMany(fetch = FetchType.EAGER, cascade=CascadeType.ALL) - @JoinTable( - name="member_role", - joinColumns={@JoinColumn(name="MEMBER_ID", referencedColumnName="ID")}, - inverseJoinColumns={@JoinColumn(name="ROLE_ID", referencedColumnName="ID")}) - private List roles = new ArrayList<>(); -} diff --git a/src/main/java/com/hotnerds/badgeroad/user/entity/Role.java b/src/main/java/com/hotnerds/badgeroad/user/entity/Role.java index 6b0993f..8b18988 100644 --- a/src/main/java/com/hotnerds/badgeroad/user/entity/Role.java +++ b/src/main/java/com/hotnerds/badgeroad/user/entity/Role.java @@ -22,7 +22,4 @@ public class Role @Column(nullable=false, unique=true) private String name; - - @ManyToMany(mappedBy="roles") - private List members; } diff --git a/src/main/java/com/hotnerds/badgeroad/user/repository/MemberRepository.java b/src/main/java/com/hotnerds/badgeroad/user/repository/MemberRepository.java deleted file mode 100644 index f377587..0000000 --- a/src/main/java/com/hotnerds/badgeroad/user/repository/MemberRepository.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.hotnerds.badgeroad.user.repository; - -import com.hotnerds.badgeroad.user.entity.Member; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface MemberRepository extends JpaRepository { - - Member findByEmail(String email); -} diff --git a/src/main/java/com/hotnerds/badgeroad/user/repository/UserRepository.java b/src/main/java/com/hotnerds/badgeroad/user/repository/UserRepository.java index e41659c..c745313 100644 --- a/src/main/java/com/hotnerds/badgeroad/user/repository/UserRepository.java +++ b/src/main/java/com/hotnerds/badgeroad/user/repository/UserRepository.java @@ -7,6 +7,5 @@ import java.util.Optional; public interface UserRepository extends JpaRepository { - @EntityGraph(attributePaths = "authorities") Optional findByEmail(String email); } diff --git a/src/main/java/com/hotnerds/badgeroad/user/service/MemberService.java b/src/main/java/com/hotnerds/badgeroad/user/service/MemberService.java deleted file mode 100644 index 18f1106..0000000 --- a/src/main/java/com/hotnerds/badgeroad/user/service/MemberService.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.hotnerds.badgeroad.user.service; - -import com.hotnerds.badgeroad.user.dto.MemberDto; -import com.hotnerds.badgeroad.user.dto.MemberLoginDto; -import com.hotnerds.badgeroad.user.entity.Member; - -import java.util.List; - -public interface MemberService { - void saveMember(MemberDto memberDto); - - Member findByEmail(String email); - - List findAllMembers(); - - Boolean loginConfirm(MemberLoginDto memberLoginDto); -} \ No newline at end of file diff --git a/src/main/java/com/hotnerds/badgeroad/user/service/MemberServiceImpl.java b/src/main/java/com/hotnerds/badgeroad/user/service/MemberServiceImpl.java deleted file mode 100644 index b788cb9..0000000 --- a/src/main/java/com/hotnerds/badgeroad/user/service/MemberServiceImpl.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.hotnerds.badgeroad.user.service; - -import com.hotnerds.badgeroad.user.dto.MemberDto; -import com.hotnerds.badgeroad.user.dto.MemberLoginDto; -import com.hotnerds.badgeroad.user.entity.Member; -import com.hotnerds.badgeroad.user.entity.Role; -import com.hotnerds.badgeroad.user.repository.MemberRepository; -import com.hotnerds.badgeroad.user.repository.RoleRepository; -import lombok.AllArgsConstructor; -import org.springframework.stereotype.Service; - -import java.util.List; -import java.util.stream.Collectors; - -@Service -@AllArgsConstructor -public class MemberServiceImpl implements MemberService { - - private MemberRepository memberRepository; - private RoleRepository roleRepository; - -// public MemberServiceImpl(MemberRepository MemberRepository, -// RoleRepository roleRepository, -// PasswordEncoder passwordEncoder) { -// this.MemberRepository = MemberRepository; -// this.roleRepository = roleRepository; -// this.passwordEncoder = passwordEncoder; -// } - - @Override - public void saveMember(MemberDto MemberDto) { - Member member = new Member(); - member.setName(MemberDto.getName()); - member.setEmail(MemberDto.getEmail()); - - //encrypt the password once we integrate spring security - //Member.setPassword(MemberDto.getPassword()); - member.setPassword(MemberDto.getPassword()); - Role role = roleRepository.findByName("ROLE_ADMIN"); - if (role == null) { - role = checkRoleExist(); - } - member.setRoles(List.of(role)); - memberRepository.save(member); - } - - @Override - public Member findByEmail(String email) { - return memberRepository.findByEmail(email); - } - - @Override - public List findAllMembers() { - List members = memberRepository.findAll(); - return members.stream().map(this::convertEntityToDto) - .collect(Collectors.toList()); - } - - @Override - public Boolean loginConfirm(MemberLoginDto memberLoginDto) { - Member member = memberRepository.findByEmail(memberLoginDto.getEmail()); - return member.getPassword().equals(memberLoginDto.getPassword()); - } - - private MemberDto convertEntityToDto(Member member) { - MemberDto memberDto = new MemberDto(); - memberDto.setName(member.getName()); - memberDto.setEmail(member.getEmail()); - return memberDto; - } - - private Role checkRoleExist() { - Role role = new Role(); - role.setName("ROLE_ADMIN"); - return roleRepository.save(role); - } -} \ No newline at end of file diff --git a/src/main/java/com/hotnerds/badgeroad/user/service/UserService.java b/src/main/java/com/hotnerds/badgeroad/user/service/UserService.java index 9c728f2..7441c71 100644 --- a/src/main/java/com/hotnerds/badgeroad/user/service/UserService.java +++ b/src/main/java/com/hotnerds/badgeroad/user/service/UserService.java @@ -1,5 +1,6 @@ package com.hotnerds.badgeroad.user.service; +import com.hotnerds.badgeroad.user.dto.LoginDto; import com.hotnerds.badgeroad.user.dto.UserDto; import com.hotnerds.badgeroad.user.entity.User; import com.hotnerds.badgeroad.user.exception.DuplicateMemberException; @@ -8,6 +9,8 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.List; + @Service @AllArgsConstructor @@ -30,7 +33,7 @@ public UserDto signup(UserDto userDto) { } @Transactional - public UserDto getUserByEmail(String email) { + public UserDto findByEmail(String email) { return UserDto.from(userRepository.findByEmail(email).orElse(null)); } @@ -41,4 +44,18 @@ public User userDtoToUser(UserDto userDto) { .nickname(userDto.getNickname()) .build(); } + + public void saveUser(User user) { + userRepository.save(user); + } + + public List findAllUsers() { + return userRepository.findAll(); + } + + public Boolean loginConfirm(LoginDto loginDto) { + + UserDto userDto = findByEmail(loginDto.getEmail()); + return loginDto.getPassword().equals(userDto.getPassword()); + } } diff --git a/src/main/java/com/hotnerds/badgeroad/user/util/SecurityUtil.java b/src/main/java/com/hotnerds/badgeroad/user/util/SecurityUtil.java deleted file mode 100644 index de00cf0..0000000 --- a/src/main/java/com/hotnerds/badgeroad/user/util/SecurityUtil.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.hotnerds.badgeroad.user.util; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.UserDetails; - -import java.util.Optional; - -public class SecurityUtil { - - private static final Logger logger = LoggerFactory.getLogger(SecurityUtil.class); - - private SecurityUtil() {} - - public static Optional getCurrentUsername() { - final Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - - if (authentication == null) { - logger.debug("Security Context에 인증 정보가 없습니다."); - return Optional.empty(); - } - - String username = null; - if (authentication.getPrincipal() instanceof UserDetails) { - UserDetails springSecurityUser = (UserDetails) authentication.getPrincipal(); - username = springSecurityUser.getUsername(); - } else if (authentication.getPrincipal() instanceof String) { - username = (String) authentication.getPrincipal(); - } - - return Optional.ofNullable(username); - } -} diff --git a/src/main/resources/application-api.yml b/src/main/resources/application-api.yml deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index fcebc01..732df3f 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -30,8 +30,7 @@ logging: level: org: hibernate: info -<<<<<<< Updated upstream -======= + # #jwt: # header: Authorization @@ -39,7 +38,6 @@ logging: # #echo 'silvernine-tech-spring-boot-jwt-tutorial-secret-silvernine-tech-spring-boot-jwt-tutorial-secret'|base64 # secret: c2lsdmVybmluZS10ZWNoLXNwcmluZy1ib290LWp3dC10dXRvcmlhbC1zZWNyZXQtc2lsdmVybmluZS10ZWNoLXNwcmluZy1ib290LWp3dC10dXRvcmlhbC1zZWNyZXQK # token-validity-in-seconds: 86400 ->>>>>>> Stashed changes naver: url: diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index 1af28c6..785dd98 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -1,9 +1,9 @@ -insert into user (username, password, nickname, activated) values ('admin', '$2a$08$lDnHPz7eUkSi6ao14Twuau08mzhWrL4kyZGGU5xfiGALO/Vxd5DOi', 'admin', 1); -insert into user (username, password, nickname, activated) values ('user', '$2a$08$UkVvwpULis18S19S5pZFn.YHPZt3oaqHZnDwqbCW9pft6uFtkXKDC', 'user', 1); +insert into user (email, password, nickname) values ('admin', 'admin', 'admin'); +insert into user (username, password, nickname, activated) values ('user', 'user', 'user'); -insert into authority (authority_name) values ('ROLE_USER'); -insert into authority (authority_name) values ('ROLE_ADMIN'); - -insert into user_authority (user_id, authority_name) values (1, 'ROLE_USER'); -insert into user_authority (user_id, authority_name) values (1, 'ROLE_ADMIN'); -insert into user_authority (user_id, authority_name) values (2, 'ROLE_USER'); \ No newline at end of file +-- insert into authority (authority_name) values ('ROLE_USER'); +-- insert into authority (authority_name) values ('ROLE_ADMIN'); +-- +-- insert into user_authority (user_id, authority_name) values (1, 'ROLE_USER'); +-- insert into user_authority (user_id, authority_name) values (1, 'ROLE_ADMIN'); +-- insert into user_authority (user_id, authority_name) values (2, 'ROLE_USER'); \ No newline at end of file diff --git a/src/main/resources/templates/login/config/CorsConfig.java b/src/main/resources/templates/login/config/CorsConfig.java deleted file mode 100644 index cd1f656..0000000 --- a/src/main/resources/templates/login/config/CorsConfig.java +++ /dev/null @@ -1,23 +0,0 @@ -package templates.login.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.cors.CorsConfiguration; -import org.springframework.web.cors.UrlBasedCorsConfigurationSource; -import org.springframework.web.filter.CorsFilter; - -@Configuration -public class CorsConfig { - @Bean - public CorsFilter corsFilter() { - UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); - CorsConfiguration config = new CorsConfiguration(); - config.setAllowCredentials(true); - config.addAllowedOrigin("*"); - config.addAllowedHeader("*"); - config.addAllowedMethod("*"); - - source.registerCorsConfiguration("/api/**", config); - return new CorsFilter(source); - } -} diff --git a/src/main/resources/templates/login/config/SecurityConfig.java b/src/main/resources/templates/login/config/SecurityConfig.java deleted file mode 100644 index c8f7c52..0000000 --- a/src/main/resources/templates/login/config/SecurityConfig.java +++ /dev/null @@ -1,89 +0,0 @@ -package templates.login.config; - -import com.hotnerds.badgeroad.user.jwt.JwtAccessDeniedHandler; -import com.hotnerds.badgeroad.user.jwt.JwtAuthenticationEntryPoint; -import com.hotnerds.badgeroad.user.jwt.JwtSecurityConfig; -import com.hotnerds.badgeroad.user.jwt.TokenProvider; -import org.springframework.context.annotation.Bean; -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; -import org.springframework.web.filter.CorsFilter; - -@EnableWebSecurity -@EnableGlobalMethodSecurity(prePostEnabled = true) -public class SecurityConfig { - private final TokenProvider tokenProvider; - private final CorsFilter corsFilter; - private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; - private final JwtAccessDeniedHandler jwtAccessDeniedHandler; - - public SecurityConfig( - TokenProvider tokenProvider, - CorsFilter corsFilter, - JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint, - JwtAccessDeniedHandler jwtAccessDeniedHandler - ) { - this.tokenProvider = tokenProvider; - this.corsFilter = corsFilter; - this.jwtAuthenticationEntryPoint = jwtAuthenticationEntryPoint; - this.jwtAccessDeniedHandler = jwtAccessDeniedHandler; - } - - @Bean - public PasswordEncoder passwordEncoder() { - return new BCryptPasswordEncoder(); - } - - @Bean - public WebSecurityCustomizer webSecurityCustomizer() { - return (web) -> web.ignoring().antMatchers("/h2-console/**" - , "/favicon.ico" - , "/error"); - } - - @Bean - public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { - httpSecurity - // token을 사용하는 방식이기 때문에 csrf를 disable합니다. - .csrf().disable() - - .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class) - - .exceptionHandling() - .authenticationEntryPoint(jwtAuthenticationEntryPoint) - .accessDeniedHandler(jwtAccessDeniedHandler) - - // enable h2-console - .and() - .headers() - .frameOptions() - .sameOrigin() - - // 세션을 사용하지 않기 때문에 STATELESS로 설정 - .and() - .sessionManagement() - .sessionCreationPolicy(SessionCreationPolicy.STATELESS) - - .and() - .authorizeRequests() - .antMatchers("/").permitAll() - .antMatchers("/user/**").permitAll() - .antMatchers("/api/hello").permitAll() - .antMatchers("/api/authenticate").permitAll() - .antMatchers("/api/signup").permitAll() - - .anyRequest().authenticated() - - .and() - .apply(new JwtSecurityConfig(tokenProvider)); - - return httpSecurity.build(); - } -} \ No newline at end of file diff --git a/src/main/resources/templates/login/controller/AuthController.java b/src/main/resources/templates/login/controller/AuthController.java deleted file mode 100644 index 6cddd55..0000000 --- a/src/main/resources/templates/login/controller/AuthController.java +++ /dev/null @@ -1,58 +0,0 @@ -package templates.login.controller; - -import com.hotnerds.badgeroad.user.dto.MemberLoginDto; -import com.hotnerds.badgeroad.user.dto.TokenDto; -import com.hotnerds.badgeroad.user.jwt.JwtFilter; -import com.hotnerds.badgeroad.user.jwt.TokenProvider; -import org.springframework.http.HttpHeaders; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -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 javax.servlet.http.HttpServletResponse; -import javax.validation.Valid; -import java.util.HashMap; -import java.util.Map; - -@RestController -@RequestMapping("/api") -public class AuthController { - private final TokenProvider tokenProvider; - private final AuthenticationManagerBuilder authenticationManagerBuilder; - - public AuthController(TokenProvider tokenProvider, AuthenticationManagerBuilder authenticationManagerBuilder) { - this.tokenProvider = tokenProvider; - this.authenticationManagerBuilder = authenticationManagerBuilder; - } - - @PostMapping("/authenticate") - public String authorize(@Valid @RequestBody MemberLoginDto memberLoginDto, HttpServletResponse response) { - - UsernamePasswordAuthenticationToken authenticationToken = - new UsernamePasswordAuthenticationToken(memberLoginDto.getUsername(), memberLoginDto.getPassword()); - - Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken); - SecurityContextHolder.getContext().setAuthentication(authentication); - - String jwt = tokenProvider.createToken(authentication); - - HttpHeaders httpHeaders = new HttpHeaders(); - httpHeaders.add(JwtFilter.AUTHORIZATION_HEADER, "Bearer " + jwt); - - Map user = new HashMap<>(); - user.put("id", memberLoginDto.getUsername()); - -// Cookie cookie = new Cookie( -// LoginCheck.COOKIE_NAME, -// jwtService.token(user, Optional.of(LocalDateTime.now().plusMinutes(30))) -// ); - - return "main"; -// return new ResponseEntity<>(new TokenDto(jwt), httpHeaders, HttpStatus.OK); - } -} diff --git a/src/main/resources/templates/login/controller/UserController.java b/src/main/resources/templates/login/controller/UserController.java deleted file mode 100644 index bf82b1b..0000000 --- a/src/main/resources/templates/login/controller/UserController.java +++ /dev/null @@ -1,56 +0,0 @@ -package templates.login.controller; - -import com.hotnerds.badgeroad.user.dto.UserDto; -import com.hotnerds.badgeroad.user.service.UserService; -import org.springframework.http.ResponseEntity; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.*; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.validation.Valid; -import java.io.IOException; - -@RestController -@RequestMapping("/api") -public class UserController { - private final UserService userService; - - public UserController(UserService userService) { - this.userService = userService; - } - - @GetMapping("/") - public String index() { - return "index"; - } - - @GetMapping("/hello") - public ResponseEntity hello() { - return ResponseEntity.ok("hello"); - } - - @PostMapping("/test-redirect") - public void testRedirect(HttpServletResponse response) throws IOException { - response.sendRedirect("/api/user"); - } - - @PostMapping("/signup") - public ResponseEntity signup( - @Valid @RequestBody UserDto userDto - ) { - return ResponseEntity.ok(userService.signup(userDto)); - } - - @GetMapping("/user") - @PreAuthorize("hasAnyRole('USER','ADMIN')") - public ResponseEntity getMyUserInfo(HttpServletRequest request) { - return ResponseEntity.ok(userService.getMyUserWithAuthorities()); - } - - @GetMapping("/user/{username}") - @PreAuthorize("hasAnyRole('ADMIN')") - public ResponseEntity getUserInfo(@PathVariable String username) { - return ResponseEntity.ok(userService.getUserWithAuthorities(username)); - } -} diff --git a/src/main/resources/templates/login/dto/AuthorityDto.java b/src/main/resources/templates/login/dto/AuthorityDto.java deleted file mode 100644 index 1dd5a86..0000000 --- a/src/main/resources/templates/login/dto/AuthorityDto.java +++ /dev/null @@ -1,12 +0,0 @@ -package templates.login.dto; - -import lombok.*; - -@Getter -@Setter -@Builder -@AllArgsConstructor -@NoArgsConstructor -public class AuthorityDto { - private String authorityName; -} \ No newline at end of file diff --git a/src/main/resources/templates/login/dto/ErrorDto.java b/src/main/resources/templates/login/dto/ErrorDto.java deleted file mode 100644 index 12f3104..0000000 --- a/src/main/resources/templates/login/dto/ErrorDto.java +++ /dev/null @@ -1,34 +0,0 @@ -package templates.login.dto; - -import org.springframework.validation.FieldError; - -import java.util.ArrayList; -import java.util.List; - -public class ErrorDto { - private final int status; - private final String message; - private List fieldErrors = new ArrayList<>(); - - public ErrorDto(int status, String message) { - this.status = status; - this.message = message; - } - - public int getStatus() { - return status; - } - - public String getMessage() { - return message; - } - - public void addFieldError(String objectName, String path, String message) { - FieldError error = new FieldError(objectName, path, message); - fieldErrors.add(error); - } - - public List getFieldErrors() { - return fieldErrors; - } -} diff --git a/src/main/resources/templates/login/dto/LoginDto.java b/src/main/resources/templates/login/dto/LoginDto.java deleted file mode 100644 index 671b7b0..0000000 --- a/src/main/resources/templates/login/dto/LoginDto.java +++ /dev/null @@ -1,22 +0,0 @@ -package templates.login.dto; - -import lombok.*; - -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - -@Getter -@Setter -@Builder -@AllArgsConstructor -@NoArgsConstructor -public class LoginDto { - - @NotNull - @Size(min = 3, max = 50) - private String username; - - @NotNull - @Size(min = 3, max = 100) - private String password; -} diff --git a/src/main/resources/templates/login/dto/TokenDto.java b/src/main/resources/templates/login/dto/TokenDto.java deleted file mode 100644 index 52b2fbb..0000000 --- a/src/main/resources/templates/login/dto/TokenDto.java +++ /dev/null @@ -1,13 +0,0 @@ -package templates.login.dto; - -import lombok.*; - -@Getter -@Setter -@Builder -@AllArgsConstructor -@NoArgsConstructor -public class TokenDto { - - private String token; -} diff --git a/src/main/resources/templates/login/dto/UserDto.java b/src/main/resources/templates/login/dto/UserDto.java deleted file mode 100644 index bae055f..0000000 --- a/src/main/resources/templates/login/dto/UserDto.java +++ /dev/null @@ -1,45 +0,0 @@ -package templates.login.dto; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.hotnerds.badgeroad.user.entity.User; -import lombok.*; - -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; -import java.util.Set; -import java.util.stream.Collectors; - -@Getter -@Setter -@Builder -@AllArgsConstructor -@NoArgsConstructor -public class UserDto { - - @NotNull - @Size(min = 3, max = 50) - private String username; - - @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) - @NotNull - @Size(min = 3, max = 100) - private String password; - - @NotNull - @Size(min = 3, max = 50) - private String nickname; - - private Set authorityDtoSet; - - public static UserDto from(User user) { - if(user == null) return null; - - return UserDto.builder() - .username(user.getUsername()) - .nickname(user.getNickname()) - .authorityDtoSet(user.getAuthorities().stream() - .map(authority -> AuthorityDto.builder().authorityName(authority.getAuthorityName()).build()) - .collect(Collectors.toSet())) - .build(); - } -} \ No newline at end of file diff --git a/src/main/resources/templates/login/entity/Authority.java b/src/main/resources/templates/login/entity/Authority.java deleted file mode 100644 index 2d6de54..0000000 --- a/src/main/resources/templates/login/entity/Authority.java +++ /dev/null @@ -1,22 +0,0 @@ -package templates.login.entity; - -import lombok.*; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Table; - -@Entity -@Table(name = "authority") -@Getter -@Setter -@Builder -@AllArgsConstructor -@NoArgsConstructor -public class Authority { - - @Id - @Column(name = "authority_name", length = 50) - private String authorityName; -} diff --git a/src/main/resources/templates/login/entity/User.java b/src/main/resources/templates/login/entity/User.java deleted file mode 100644 index fcc41ba..0000000 --- a/src/main/resources/templates/login/entity/User.java +++ /dev/null @@ -1,40 +0,0 @@ -package templates.login.entity; - -import lombok.*; - -import javax.persistence.*; -import java.util.Set; - -@Entity -@Table(name = "`user`") -@Getter -@Setter -@Builder -@AllArgsConstructor -@NoArgsConstructor -public class User { - - @Id - @Column(name = "user_id") - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long userId; - - @Column(name = "username", length = 50, unique = true) - private String username; - - @Column(name = "password", length = 100) - private String password; - - @Column(name = "nickname", length = 50) - private String nickname; - - @Column(name = "activated") - private boolean activated; - - @ManyToMany - @JoinTable( - name = "user_authority", - joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "user_id")}, - inverseJoinColumns = {@JoinColumn(name = "authority_name", referencedColumnName = "authority_name")}) - private Set authorities; -} diff --git a/src/main/resources/templates/login/exception/DuplicateMemberException.java b/src/main/resources/templates/login/exception/DuplicateMemberException.java deleted file mode 100644 index 8d4c35b..0000000 --- a/src/main/resources/templates/login/exception/DuplicateMemberException.java +++ /dev/null @@ -1,16 +0,0 @@ -package templates.login.exception; - -public class DuplicateMemberException extends RuntimeException { - public DuplicateMemberException() { - super(); - } - public DuplicateMemberException(String message, Throwable cause) { - super(message, cause); - } - public DuplicateMemberException(String message) { - super(message); - } - public DuplicateMemberException(Throwable cause) { - super(cause); - } -} diff --git a/src/main/resources/templates/login/exception/NotFoundMemberException.java b/src/main/resources/templates/login/exception/NotFoundMemberException.java deleted file mode 100644 index 2e31504..0000000 --- a/src/main/resources/templates/login/exception/NotFoundMemberException.java +++ /dev/null @@ -1,16 +0,0 @@ -package templates.login.exception; - -public class NotFoundMemberException extends RuntimeException { - public NotFoundMemberException() { - super(); - } - public NotFoundMemberException(String message, Throwable cause) { - super(message, cause); - } - public NotFoundMemberException(String message) { - super(message); - } - public NotFoundMemberException(Throwable cause) { - super(cause); - } -} diff --git a/src/main/resources/templates/login/handler/MethodArgumentNotValidExceptionHandler.java b/src/main/resources/templates/login/handler/MethodArgumentNotValidExceptionHandler.java deleted file mode 100644 index 3300418..0000000 --- a/src/main/resources/templates/login/handler/MethodArgumentNotValidExceptionHandler.java +++ /dev/null @@ -1,37 +0,0 @@ -package templates.login.handler; - -import com.hotnerds.badgeroad.user.dto.ErrorDto; -import org.springframework.core.Ordered; -import org.springframework.core.annotation.Order; -import org.springframework.validation.BindingResult; -import org.springframework.web.bind.MethodArgumentNotValidException; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.ResponseStatus; - -import java.util.List; - -import static org.springframework.http.HttpStatus.BAD_REQUEST; - -@Order(Ordered.HIGHEST_PRECEDENCE) -@ControllerAdvice -public class MethodArgumentNotValidExceptionHandler { - - @ResponseStatus(BAD_REQUEST) - @ResponseBody - @ExceptionHandler(MethodArgumentNotValidException.class) - public ErrorDto methodArgumentNotValidException(MethodArgumentNotValidException ex) { - BindingResult result = ex.getBindingResult(); - List fieldErrors = result.getFieldErrors(); - return processFieldErrors(fieldErrors); - } - - private ErrorDto processFieldErrors(List fieldErrors) { - ErrorDto errorDTO = new ErrorDto(BAD_REQUEST.value(), "@Valid Error"); - for (org.springframework.validation.FieldError fieldError: fieldErrors) { - errorDTO.addFieldError(fieldError.getObjectName(), fieldError.getField(), fieldError.getDefaultMessage()); - } - return errorDTO; - } -} \ No newline at end of file diff --git a/src/main/resources/templates/login/handler/RestResponseExceptionHandler.java b/src/main/resources/templates/login/handler/RestResponseExceptionHandler.java deleted file mode 100644 index eff3038..0000000 --- a/src/main/resources/templates/login/handler/RestResponseExceptionHandler.java +++ /dev/null @@ -1,33 +0,0 @@ -package templates.login.handler; - -import com.hotnerds.badgeroad.user.dto.ErrorDto; -import com.hotnerds.badgeroad.user.exception.DuplicateMemberException; -import com.hotnerds.badgeroad.user.exception.NotFoundMemberException; -import org.springframework.security.access.AccessDeniedException; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.ResponseStatus; -import org.springframework.web.context.request.WebRequest; -import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; - -import static org.springframework.http.HttpStatus.CONFLICT; -import static org.springframework.http.HttpStatus.FORBIDDEN; - -@ControllerAdvice -public class RestResponseExceptionHandler extends ResponseEntityExceptionHandler { - - @ResponseStatus(CONFLICT) - @ExceptionHandler(value = { DuplicateMemberException.class }) - @ResponseBody - protected ErrorDto badRequest(RuntimeException ex, WebRequest request) { - return new ErrorDto(CONFLICT.value(), ex.getMessage()); - } - - @ResponseStatus(FORBIDDEN) - @ExceptionHandler(value = { NotFoundMemberException.class, AccessDeniedException.class }) - @ResponseBody - protected ErrorDto forbidden(RuntimeException ex, WebRequest request) { - return new ErrorDto(FORBIDDEN.value(), ex.getMessage()); - } -} \ No newline at end of file diff --git a/src/main/resources/templates/login/jwt/JwtAccessDeniedHandler.java b/src/main/resources/templates/login/jwt/JwtAccessDeniedHandler.java deleted file mode 100644 index 511d48e..0000000 --- a/src/main/resources/templates/login/jwt/JwtAccessDeniedHandler.java +++ /dev/null @@ -1,18 +0,0 @@ -package templates.login.jwt; - -import org.springframework.security.access.AccessDeniedException; -import org.springframework.security.web.access.AccessDeniedHandler; -import org.springframework.stereotype.Component; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; - -@Component -public class JwtAccessDeniedHandler implements AccessDeniedHandler { - @Override - public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException { - //필요한 권한이 없이 접근하려 할때 403 - response.sendError(HttpServletResponse.SC_FORBIDDEN); - } -} diff --git a/src/main/resources/templates/login/jwt/JwtAuthenticationEntryPoint.java b/src/main/resources/templates/login/jwt/JwtAuthenticationEntryPoint.java deleted file mode 100644 index b68a60f..0000000 --- a/src/main/resources/templates/login/jwt/JwtAuthenticationEntryPoint.java +++ /dev/null @@ -1,20 +0,0 @@ -package templates.login.jwt; - -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.web.AuthenticationEntryPoint; -import org.springframework.stereotype.Component; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; - -@Component -public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { - @Override - public void commence(HttpServletRequest request, - HttpServletResponse response, - AuthenticationException authException) throws IOException { - // 유효한 자격증명을 제공하지 않고 접근하려 할때 401 - response.sendError(HttpServletResponse.SC_UNAUTHORIZED); - } -} diff --git a/src/main/resources/templates/login/jwt/JwtFilter.java b/src/main/resources/templates/login/jwt/JwtFilter.java deleted file mode 100644 index 0e176ad..0000000 --- a/src/main/resources/templates/login/jwt/JwtFilter.java +++ /dev/null @@ -1,52 +0,0 @@ -package templates.login.jwt; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.util.StringUtils; -import org.springframework.web.filter.GenericFilterBean; - -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; - -public class JwtFilter extends GenericFilterBean { - - private static final Logger logger = LoggerFactory.getLogger(JwtFilter.class); - public static final String AUTHORIZATION_HEADER = "Authorization"; - private TokenProvider tokenProvider; - public JwtFilter(TokenProvider tokenProvider) { - this.tokenProvider = tokenProvider; - } - - @Override - public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { - HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest; - String jwt = resolveToken(httpServletRequest); - String requestURI = httpServletRequest.getRequestURI(); - - if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) { - Authentication authentication = tokenProvider.getAuthentication(jwt); - SecurityContextHolder.getContext().setAuthentication(authentication); - logger.debug("Security Context에 '{}' 인증 정보를 저장했습니다, uri: {}", authentication.getName(), requestURI); - } else { - logger.debug("유효한 JWT 토큰이 없습니다, uri: {}", requestURI); - } - - filterChain.doFilter(servletRequest, servletResponse); - } - - private String resolveToken(HttpServletRequest request) { - String bearerToken = request.getHeader(AUTHORIZATION_HEADER); - - if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { - return bearerToken.substring(7); - } - - return null; - } -} diff --git a/src/main/resources/templates/login/jwt/JwtSecurityConfig.java b/src/main/resources/templates/login/jwt/JwtSecurityConfig.java deleted file mode 100644 index c3782c8..0000000 --- a/src/main/resources/templates/login/jwt/JwtSecurityConfig.java +++ /dev/null @@ -1,21 +0,0 @@ -package templates.login.jwt; - -import org.springframework.security.config.annotation.SecurityConfigurerAdapter; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.web.DefaultSecurityFilterChain; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; - -public class JwtSecurityConfig extends SecurityConfigurerAdapter { - private TokenProvider tokenProvider; - public JwtSecurityConfig(TokenProvider tokenProvider) { - this.tokenProvider = tokenProvider; - } - - @Override - public void configure(HttpSecurity http) { - http.addFilterBefore( - new JwtFilter(tokenProvider), - UsernamePasswordAuthenticationFilter.class - ); - } -} diff --git a/src/main/resources/templates/login/jwt/TokenProvider.java b/src/main/resources/templates/login/jwt/TokenProvider.java deleted file mode 100644 index 71775a6..0000000 --- a/src/main/resources/templates/login/jwt/TokenProvider.java +++ /dev/null @@ -1,94 +0,0 @@ -package templates.login.jwt; - -import io.jsonwebtoken.*; -import io.jsonwebtoken.io.Decoders; -import io.jsonwebtoken.security.Keys; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.userdetails.User; -import org.springframework.stereotype.Component; - -import java.security.Key; -import java.util.Arrays; -import java.util.Collection; -import java.util.Date; -import java.util.stream.Collectors; - -@Component -public class TokenProvider implements InitializingBean { - - private final Logger logger = LoggerFactory.getLogger(TokenProvider.class); - private static final String AUTHORITIES_KEY = "auth"; - private final String secret; - private final long tokenValidityInMilliseconds; - private Key key; - - public TokenProvider( - @Value("${jwt.secret}") String secret, - @Value("${jwt.token-validity-in-seconds}") long tokenValidityInSeconds) { - this.secret = secret; - this.tokenValidityInMilliseconds = tokenValidityInSeconds * 1000; - } - - @Override - public void afterPropertiesSet() { - byte[] keyBytes = Decoders.BASE64.decode(secret); - this.key = Keys.hmacShaKeyFor(keyBytes); - } - - public String createToken(Authentication authentication) { - String authorities = authentication.getAuthorities().stream() - .map(GrantedAuthority::getAuthority) - .collect(Collectors.joining(",")); - - long now = (new Date()).getTime(); - Date validity = new Date(now + this.tokenValidityInMilliseconds); - - return Jwts.builder() - .setSubject(authentication.getName()) - .claim(AUTHORITIES_KEY, authorities) - .signWith(key, SignatureAlgorithm.HS512) - .setExpiration(validity) - .compact(); - } - - public Authentication getAuthentication(String token) { - Claims claims = Jwts - .parserBuilder() - .setSigningKey(key) - .build() - .parseClaimsJws(token) - .getBody(); - - Collection authorities = - Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(",")) - .map(SimpleGrantedAuthority::new) - .collect(Collectors.toList()); - - User principal = new User(claims.getSubject(), "", authorities); - - return new UsernamePasswordAuthenticationToken(principal, token, authorities); - } - - public boolean validateToken(String token) { - try { - Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token); - return true; - } catch (io.jsonwebtoken.security.SecurityException | MalformedJwtException e) { - logger.info("잘못된 JWT 서명입니다."); - } catch (ExpiredJwtException e) { - logger.info("만료된 JWT 토큰입니다."); - } catch (UnsupportedJwtException e) { - logger.info("지원되지 않는 JWT 토큰입니다."); - } catch (IllegalArgumentException e) { - logger.info("JWT 토큰이 잘못되었습니다."); - } - return false; - } -} diff --git a/src/main/resources/templates/login/repository/AuthorityRepository.java b/src/main/resources/templates/login/repository/AuthorityRepository.java deleted file mode 100644 index e5dc88f..0000000 --- a/src/main/resources/templates/login/repository/AuthorityRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package templates.login.repository; - -import com.hotnerds.badgeroad.user.entity.Authority; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface AuthorityRepository extends JpaRepository { -} diff --git a/src/main/resources/templates/login/repository/UserRepository.java b/src/main/resources/templates/login/repository/UserRepository.java deleted file mode 100644 index 9df8a77..0000000 --- a/src/main/resources/templates/login/repository/UserRepository.java +++ /dev/null @@ -1,12 +0,0 @@ -package templates.login.repository; - -import com.hotnerds.badgeroad.user.entity.User; -import org.springframework.data.jpa.repository.EntityGraph; -import org.springframework.data.jpa.repository.JpaRepository; - -import java.util.Optional; - -public interface UserRepository extends JpaRepository { - @EntityGraph(attributePaths = "authorities") - Optional findOneWithAuthoritiesByUsername(String username); -} diff --git a/src/main/resources/templates/login/service/CustomUserDetailsService.java b/src/main/resources/templates/login/service/CustomUserDetailsService.java deleted file mode 100644 index ced7126..0000000 --- a/src/main/resources/templates/login/service/CustomUserDetailsService.java +++ /dev/null @@ -1,45 +0,0 @@ -package templates.login.service; - -import com.hotnerds.badgeroad.user.entity.User; -import com.hotnerds.badgeroad.user.repository.UserRepository; -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.Component; -import org.springframework.transaction.annotation.Transactional; - -import java.util.List; -import java.util.stream.Collectors; - -@Component("userDetailsService") -public class CustomUserDetailsService implements UserDetailsService { - private final UserRepository userRepository; - - public CustomUserDetailsService(UserRepository userRepository) { - this.userRepository = userRepository; - } - - @Override - @Transactional - public UserDetails loadUserByUsername(final String username) { - return userRepository.findOneWithAuthoritiesByUsername(username) - .map(user -> createUser(username, user)) - .orElseThrow(() -> new UsernameNotFoundException(username + " -> 데이터베이스에서 찾을 수 없습니다.")); - } - - private org.springframework.security.core.userdetails.User createUser(String username, User user) { - if (!user.isActivated()) { - throw new RuntimeException(username + " -> 활성화되어 있지 않습니다."); - } - - List grantedAuthorities = user.getAuthorities().stream() - .map(authority -> new SimpleGrantedAuthority(authority.getAuthorityName())) - .collect(Collectors.toList()); - - return new org.springframework.security.core.userdetails.User(user.getUsername(), - user.getPassword(), - grantedAuthorities); - } -} diff --git a/src/main/resources/templates/login/service/UserService.java b/src/main/resources/templates/login/service/UserService.java deleted file mode 100644 index 3912b04..0000000 --- a/src/main/resources/templates/login/service/UserService.java +++ /dev/null @@ -1,60 +0,0 @@ -package templates.login.service; - -import com.hotnerds.badgeroad.user.dto.UserDto; -import com.hotnerds.badgeroad.user.entity.Authority; -import com.hotnerds.badgeroad.user.entity.User; -import com.hotnerds.badgeroad.user.exception.DuplicateMemberException; -import com.hotnerds.badgeroad.user.exception.NotFoundMemberException; -import com.hotnerds.badgeroad.user.repository.UserRepository; -import com.hotnerds.badgeroad.user.util.SecurityUtil; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.Collections; - -@Service -public class UserService { - private final UserRepository userRepository; - private final PasswordEncoder passwordEncoder; - - public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) { - this.userRepository = userRepository; - this.passwordEncoder = passwordEncoder; - } - - @Transactional - public UserDto signup(UserDto userDto) { - if (userRepository.findOneWithAuthoritiesByUsername(userDto.getUsername()).orElse(null) != null) { - throw new DuplicateMemberException("이미 가입되어 있는 유저입니다."); - } - - Authority authority = Authority.builder() - .authorityName("ROLE_USER") - .build(); - - User user = User.builder() - .username(userDto.getUsername()) - .password(passwordEncoder.encode(userDto.getPassword())) - .nickname(userDto.getNickname()) - .authorities(Collections.singleton(authority)) - .activated(true) - .build(); - - return UserDto.from(userRepository.save(user)); - } - - @Transactional(readOnly = true) - public UserDto getUserWithAuthorities(String username) { - return UserDto.from(userRepository.findOneWithAuthoritiesByUsername(username).orElse(null)); - } - - @Transactional(readOnly = true) - public UserDto getMyUserWithAuthorities() { - return UserDto.from( - SecurityUtil.getCurrentUsername() - .flatMap(userRepository::findOneWithAuthoritiesByUsername) - .orElseThrow(() -> new NotFoundMemberException("Member not found")) - ); - } -} diff --git a/src/main/resources/templates/login/util/SecurityUtil.java b/src/main/resources/templates/login/util/SecurityUtil.java deleted file mode 100644 index 40999b6..0000000 --- a/src/main/resources/templates/login/util/SecurityUtil.java +++ /dev/null @@ -1,35 +0,0 @@ -package templates.login.util; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.UserDetails; - -import java.util.Optional; - -public class SecurityUtil { - - private static final Logger logger = LoggerFactory.getLogger(SecurityUtil.class); - - private SecurityUtil() {} - - public static Optional getCurrentUsername() { - final Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - - if (authentication == null) { - logger.debug("Security Context에 인증 정보가 없습니다."); - return Optional.empty(); - } - - String username = null; - if (authentication.getPrincipal() instanceof UserDetails) { - UserDetails springSecurityUser = (UserDetails) authentication.getPrincipal(); - username = springSecurityUser.getUsername(); - } else if (authentication.getPrincipal() instanceof String) { - username = (String) authentication.getPrincipal(); - } - - return Optional.ofNullable(username); - } -} diff --git a/src/main/resources/templates/main.html b/src/main/resources/templates/main.html index d3790b1..706303f 100644 --- a/src/main/resources/templates/main.html +++ b/src/main/resources/templates/main.html @@ -4,7 +4,7 @@ -

+

HOME

LOGIN

SIGNUP

diff --git a/src/main/resources/trash/config/SecurityConfig.java b/src/main/resources/trash/config/SecurityConfig.java deleted file mode 100644 index 06f46a6..0000000 --- a/src/main/resources/trash/config/SecurityConfig.java +++ /dev/null @@ -1,98 +0,0 @@ -package com.hotnerds.badgeroad.config; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -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.annotation.web.configurers.LogoutConfigurer; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.AuthenticationException; -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 -@EnableGlobalMethodSecurity( - securedEnabled = true, - jsr250Enabled = true, - prePostEnabled = true -) -public class SecurityConfig{ - -// private final ObjectMapper objectMapper; - @Autowired - private UserDetailsService userDetailsService; - - private static final String[] AUTH_WHITELIST = { - "open/**" - }; - - @Bean - public static PasswordEncoder passwordEncoder() { - return new BCryptPasswordEncoder(); - } - - @Bean - public WebSecurityCustomizer configure() { - return web -> web.ignoring().mvcMatchers(AUTH_WHITELIST); - } - - @Bean - public AuthenticationManager authenticationManagerBean() throws Exception { - return new AuthenticationManager() { - @Override - public Authentication authenticate(Authentication authentication) throws AuthenticationException { - return null; - } - }; - } - - @Bean - public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - http.csrf().disable() - .authorizeRequests() - .antMatchers("/signup/**").permitAll() - .antMatchers("/index").permitAll() - .antMatchers("/members").hasRole("ADMIN") - .and(). - formLogin( - form -> form - .loginPage("/login") - .loginProcessingUrl("/login") - .defaultSuccessUrl("/members") - .permitAll() - ).logout( - logout -> logout - .logoutRequestMatcher(new AntPathRequestMatcher("/logout")) - .permitAll() - ); - return http.build(); - } - - @Autowired - public void configure(AuthenticationManagerBuilder auth) throws Exception { - auth - .userDetailsService(userDetailsService) - .passwordEncoder(passwordEncoder()); - } - -// @Bean -// public UserDetailsService userDetailsService() { -// UserDetails user = -// User.withUserDetails() -// .username("user") -// .password("password") -// .roles("USER") -// .build(); -// -// return new InMemoryUserDetailsManager(user); -// } -} diff --git a/src/main/resources/trash/controller/AuthController.java b/src/main/resources/trash/controller/AuthController.java deleted file mode 100644 index 95bf4cf..0000000 --- a/src/main/resources/trash/controller/AuthController.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.hotnerds.badgeroad.controller; - -import com.hotnerds.badgeroad.dto.MemberDto; -import com.hotnerds.badgeroad.entity.Member; -import com.hotnerds.badgeroad.service.MemberService; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.validation.BindingResult; -import org.springframework.web.bind.annotation.*; - -import javax.validation.Valid; -import java.util.List; - -@Controller -public class AuthController { - private final MemberService memberService; - - public AuthController(MemberService memberService) { - this.memberService = memberService; - } - - @GetMapping("index") - public String homepage(){ - return "index"; - } - - @GetMapping("/login") - public String loginForm() { - return "login"; - } - - @GetMapping("/signup") - public String showRegistrationForm(Model model){ - MemberDto member = new MemberDto(); - model.addAttribute("member", member); - return "signup"; - } - - @GetMapping("/common") - public String common() { - return "common"; - } - - -// -// @PostMapping("/login") -// public String loginConfirm() { -// return "login"; -// } - - // handler method to handle Member registration request - - - // handler method to handle register Member form submit request - @PostMapping("/signup") - public String registration(@Valid @ModelAttribute("Member") MemberDto member, - BindingResult result, - Model model){ - Member existing = memberService.findByEmail(member.getEmail()); - if (existing != null) { - result.rejectValue("email", null, "There is already an account registered with that email"); - } - if (result.hasErrors()) { - model.addAttribute("member", member); - return "signup"; - } - memberService.saveMember(member); - return "redirect:/login"; - } - - @GetMapping("/members") - public String listRegisteredMembers(Model model){ - List members = memberService.findAllMembers(); - model.addAttribute("Members", members); - return "members"; - } -} diff --git a/src/main/resources/trash/controller/HomeController.java b/src/main/resources/trash/controller/HomeController.java deleted file mode 100644 index 02b9652..0000000 --- a/src/main/resources/trash/controller/HomeController.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.hotnerds.badgeroad.controller; - -import com.hotnerds.badgeroad.dto.MemberDto; - -public class HomeController { - - -} diff --git a/src/main/resources/trash/dto/MemberDto.java b/src/main/resources/trash/dto/MemberDto.java deleted file mode 100644 index c691632..0000000 --- a/src/main/resources/trash/dto/MemberDto.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.hotnerds.badgeroad.dto; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import javax.validation.constraints.Email; -import javax.validation.constraints.NotEmpty; - -@Getter -@Setter -@NoArgsConstructor -@AllArgsConstructor -public class MemberDto -{ - private Long id; - @NotEmpty(message = "Email should not be empty") - @Email - private String email; - @NotEmpty(message = "Password should not be empty") - private String password; - @NotEmpty(message = "name should not be empty") - private String name; -} \ No newline at end of file diff --git a/src/main/resources/trash/dto/MemberSignupRequestDto.java b/src/main/resources/trash/dto/MemberSignupRequestDto.java deleted file mode 100644 index 99bbd4a..0000000 --- a/src/main/resources/trash/dto/MemberSignupRequestDto.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.hotnerds.badgeroad.dto; - -import lombok.Getter; -import lombok.Setter; - -@Getter -@Setter -public class MemberSignupRequestDto { - private String email; - private String password; - private String name; -} diff --git a/src/main/resources/trash/entity/Member.java b/src/main/resources/trash/entity/Member.java deleted file mode 100644 index cea5771..0000000 --- a/src/main/resources/trash/entity/Member.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.hotnerds.badgeroad.entity; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import javax.persistence.*; -import java.util.ArrayList; -import java.util.List; - -@Getter -@Setter -@NoArgsConstructor -@AllArgsConstructor -@Entity -@Table(name = "member") -public class Member { - - private static final long serialVersionUID = 1L; - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @Column(nullable=false) - private String name; - - @Column(nullable=false, unique=true) - private String email; - - @Column(nullable=false) - private String password; - - @ManyToMany(fetch = FetchType.EAGER, cascade=CascadeType.ALL) - @JoinTable( - name="member_role", - joinColumns={@JoinColumn(name="MEMBER_ID", referencedColumnName="ID")}, - inverseJoinColumns={@JoinColumn(name="ROLE_ID", referencedColumnName="ID")}) - private List roles = new ArrayList<>(); -} diff --git a/src/main/resources/trash/entity/Role.java b/src/main/resources/trash/entity/Role.java deleted file mode 100644 index fe4cbb4..0000000 --- a/src/main/resources/trash/entity/Role.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.hotnerds.badgeroad.entity; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import javax.persistence.*; -import java.util.List; - -@Setter -@Getter -@NoArgsConstructor -@AllArgsConstructor -@Entity -@Table(name="role") -public class Role -{ - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @Column(nullable=false, unique=true) - private String name; - - @ManyToMany(mappedBy="roles") - private List members; -} diff --git a/src/main/resources/trash/login.html b/src/main/resources/trash/login.html deleted file mode 100644 index c1e4ea9..0000000 --- a/src/main/resources/trash/login.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - Registration and Login System - - - - -
-
-
-
-
-
-
-
Invalid Email and Password.
-
-
-
You have been logged out.
-
-
-
-

Login Form

-
-
-
-
- - -
- -
- - -
- -
- - Not registered? - Register/SignUp Here - -
-
-
-
-
-
-
- - \ No newline at end of file diff --git a/src/main/resources/trash/repository/MemberRepository.java b/src/main/resources/trash/repository/MemberRepository.java deleted file mode 100644 index 26a3d92..0000000 --- a/src/main/resources/trash/repository/MemberRepository.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.hotnerds.badgeroad.repository; - -import com.hotnerds.badgeroad.entity.Member; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface MemberRepository extends JpaRepository { - - Member findByEmail(String email); -} diff --git a/src/main/resources/trash/repository/RoleRepository.java b/src/main/resources/trash/repository/RoleRepository.java deleted file mode 100644 index cbbf01a..0000000 --- a/src/main/resources/trash/repository/RoleRepository.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.hotnerds.badgeroad.repository; - -import com.hotnerds.badgeroad.entity.Role; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface RoleRepository extends JpaRepository { - Role findByName(String name); -} diff --git a/src/main/resources/trash/service/CustomUserDetailsService.java b/src/main/resources/trash/service/CustomUserDetailsService.java deleted file mode 100644 index 535f189..0000000 --- a/src/main/resources/trash/service/CustomUserDetailsService.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.hotnerds.badgeroad.service; - -import com.hotnerds.badgeroad.entity.Member; -import com.hotnerds.badgeroad.entity.Role; -import com.hotnerds.badgeroad.repository.MemberRepository; -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 java.util.Collection; -import java.util.stream.Collectors; - -@Service -public class CustomUserDetailsService implements UserDetailsService { - private final MemberRepository memberRepository; - - public CustomUserDetailsService(MemberRepository MemberRepository) { - this.memberRepository = MemberRepository; - } - - @Override - public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { - Member member = memberRepository.findByEmail(email); - - if (member != null) { - return new org.springframework.security.core.userdetails.User(member.getEmail(), - member.getPassword(), - mapRolesToAuthorities(member.getRoles())); - }else{ - throw new UsernameNotFoundException("Invalid username or password."); - } - } - - private Collection< ? extends GrantedAuthority> mapRolesToAuthorities(Collection roles) { - Collection < ? extends GrantedAuthority> mapRoles = roles.stream() - .map(role -> new SimpleGrantedAuthority(role.getName())) - .collect(Collectors.toList()); - return mapRoles; - } -} diff --git a/src/main/resources/trash/service/MemberService.java b/src/main/resources/trash/service/MemberService.java deleted file mode 100644 index 9c80395..0000000 --- a/src/main/resources/trash/service/MemberService.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.hotnerds.badgeroad.service; - -import com.hotnerds.badgeroad.dto.MemberDto; -import com.hotnerds.badgeroad.entity.Member; - -import java.util.List; - -public interface MemberService { - void saveMember(MemberDto memberDto); - - Member findByEmail(String email); - - List findAllMembers(); -} \ No newline at end of file diff --git a/src/main/resources/trash/service/MemberServiceImpl.java b/src/main/resources/trash/service/MemberServiceImpl.java deleted file mode 100644 index 6a0287e..0000000 --- a/src/main/resources/trash/service/MemberServiceImpl.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.hotnerds.badgeroad.service; - -import com.hotnerds.badgeroad.dto.MemberDto; -import com.hotnerds.badgeroad.entity.Member; -import com.hotnerds.badgeroad.entity.Role; -import com.hotnerds.badgeroad.repository.MemberRepository; -import com.hotnerds.badgeroad.repository.RoleRepository; -import lombok.AllArgsConstructor; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.stereotype.Service; - -import java.util.List; -import java.util.stream.Collectors; - -@Service -@AllArgsConstructor -public class MemberServiceImpl implements MemberService { - - private MemberRepository MemberRepository; - private RoleRepository roleRepository; - private PasswordEncoder passwordEncoder; - -// public MemberServiceImpl(MemberRepository MemberRepository, -// RoleRepository roleRepository, -// PasswordEncoder passwordEncoder) { -// this.MemberRepository = MemberRepository; -// this.roleRepository = roleRepository; -// this.passwordEncoder = passwordEncoder; -// } - - @Override - public void saveMember(MemberDto MemberDto) { - Member member = new Member(); - member.setName(MemberDto.getName()); - member.setEmail(MemberDto.getEmail()); - - //encrypt the password once we integrate spring security - //Member.setPassword(MemberDto.getPassword()); - member.setPassword(passwordEncoder.encode(MemberDto.getPassword())); - Role role = roleRepository.findByName("ROLE_ADMIN"); - if (role == null) { - role = checkRoleExist(); - } - member.setRoles(List.of(role)); - MemberRepository.save(member); - } - - @Override - public Member findByEmail(String email) { - return MemberRepository.findByEmail(email); - } - - @Override - public List findAllMembers() { - List members = MemberRepository.findAll(); - return members.stream().map(this::convertEntityToDto) - .collect(Collectors.toList()); - } - - private MemberDto convertEntityToDto(Member member) { - MemberDto memberDto = new MemberDto(); - memberDto.setName(member.getName()); - memberDto.setEmail(member.getEmail()); - return memberDto; - } - - private Role checkRoleExist() { - Role role = new Role(); - role.setName("ROLE_ADMIN"); - return roleRepository.save(role); - } -} \ No newline at end of file diff --git a/src/main/resources/trash/yamlreadDB/ApplicationDBRead.java b/src/main/resources/trash/yamlreadDB/ApplicationDBRead.java deleted file mode 100644 index e71bfaf..0000000 --- a/src/main/resources/trash/yamlreadDB/ApplicationDBRead.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.hotnerds.badgeroad.yamlreadDB; - -import lombok.Getter; -import lombok.Setter; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.PropertySource; - -@Configuration -//value를 통해 값이 있는 위치를 명시해준다. -@PropertySource(value = "classpath:application.yml", factory = YamlPropertySourceFactory.class) -// yml 파일에서 가져올 변수 이름을 명시해준다. -@ConfigurationProperties(prefix = "spring.datasource") -@Setter -@Getter -public class ApplicationDBRead { - private DBSource dbSource; -} \ No newline at end of file diff --git a/src/main/resources/trash/yamlreadDB/DBSource.java b/src/main/resources/trash/yamlreadDB/DBSource.java deleted file mode 100644 index c48f8cb..0000000 --- a/src/main/resources/trash/yamlreadDB/DBSource.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.hotnerds.badgeroad.yamlreadDB; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@Getter -@Setter -@NoArgsConstructor -@AllArgsConstructor -public class DBSource { - private String driver; - private String url; - private String username; - private String password; -} diff --git a/src/main/resources/trash/yamlreadDB/YamlPropertySourceFactory.java b/src/main/resources/trash/yamlreadDB/YamlPropertySourceFactory.java deleted file mode 100644 index ab51009..0000000 --- a/src/main/resources/trash/yamlreadDB/YamlPropertySourceFactory.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.hotnerds.badgeroad.yamlreadDB; - -import org.springframework.beans.factory.config.YamlPropertiesFactoryBean; -import org.springframework.core.env.PropertiesPropertySource; -import org.springframework.core.env.PropertySource; -import org.springframework.core.io.support.EncodedResource; -import org.springframework.core.io.support.PropertySourceFactory; -import org.springframework.lang.Nullable; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.Properties; - -public class YamlPropertySourceFactory implements PropertySourceFactory { - - @Override - public PropertySource createPropertySource(@Nullable String name, EncodedResource resource) throws IOException { - Properties propertiesFromYaml = loadYamlIntoProperties(resource); - String sourceName = name != null ? name : resource.getResource().getFilename(); - return new PropertiesPropertySource(sourceName, propertiesFromYaml); - } - - private Properties loadYamlIntoProperties(EncodedResource resource) throws FileNotFoundException { - try { - YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean(); - factory.setResources(resource.getResource()); - factory.afterPropertiesSet(); - return factory.getObject(); - } catch (IllegalStateException e) { - // for ignoreResourceNotFound - Throwable cause = e.getCause(); - if (cause instanceof FileNotFoundException) - throw (FileNotFoundException) e.getCause(); - throw e; - } - } -} From 3d9a65fb6e5c0194a1059e8cbff113faed0a186a Mon Sep 17 00:00:00 2001 From: shinjbin Date: Thu, 15 Dec 2022 17:19:06 +0900 Subject: [PATCH 05/11] init --- pom.xml | 4 ++ .../com/hotnerds/badgeroad/JDBCTests.java | 58 +++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 src/test/java/com/hotnerds/badgeroad/JDBCTests.java diff --git a/pom.xml b/pom.xml index 18595e4..a7bc456 100644 --- a/pom.xml +++ b/pom.xml @@ -65,6 +65,10 @@ spring-boot-configuration-processor true + + org.springframework.boot + spring-boot-starter-validation + diff --git a/src/test/java/com/hotnerds/badgeroad/JDBCTests.java b/src/test/java/com/hotnerds/badgeroad/JDBCTests.java new file mode 100644 index 0000000..d7c511d --- /dev/null +++ b/src/test/java/com/hotnerds/badgeroad/JDBCTests.java @@ -0,0 +1,58 @@ +package com.hotnerds.badgeroad; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import java.sql.Connection; +import java.sql.DriverManager; + +import static org.junit.Assert.fail; + +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest +public class JDBCTests { + @Before + public void Setup() { + + } + + @Value("${spring.datasource.url}") + String url_; + + @Value("${spring.datasource.user}") + String user_; + + @Value("${spring.datasource.password}") + String password_; + + static { + try { + Class.forName("com.mysql.cj.jdbc.Driver"); + } catch(Exception e) { + e.printStackTrace(); + } + } + + @Test + public void testConnection() { + + String url = "jdbc:mysql://localhost:3306/badgeroad?useSSL=false&allowPublicKeyRetrieval=true"; + String user = "root"; + String password = "jeong1998"; + try(Connection con = + DriverManager.getConnection( + url, + user, + password)){ + System.out.println(con); + } catch (Exception e) { + fail(e.getMessage()); + } + + } +} From a0fa0a6afe68554fcfc5c45d9cef3a8669232c49 Mon Sep 17 00:00:00 2001 From: shinjbin Date: Fri, 16 Dec 2022 04:28:42 +0900 Subject: [PATCH 06/11] init --- src/main/resources/application.yml | 6 ++++-- src/test/java/com/hotnerds/badgeroad/JDBCTests.java | 11 +---------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 732df3f..1851d58 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -12,10 +12,12 @@ spring: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/badgeroad?useSSL=false&allowPublicKeyRetrieval=true username: root - password: jeong1998# - + password: jeong1998 profiles: include: API-KEY + sql: + init: + mode: always jpa: database: mysql diff --git a/src/test/java/com/hotnerds/badgeroad/JDBCTests.java b/src/test/java/com/hotnerds/badgeroad/JDBCTests.java index d7c511d..3642cbc 100644 --- a/src/test/java/com/hotnerds/badgeroad/JDBCTests.java +++ b/src/test/java/com/hotnerds/badgeroad/JDBCTests.java @@ -1,30 +1,21 @@ package com.hotnerds.badgeroad; -import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import java.sql.Connection; import java.sql.DriverManager; import static org.junit.Assert.fail; -@RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest public class JDBCTests { - @Before - public void Setup() { - - } @Value("${spring.datasource.url}") String url_; - @Value("${spring.datasource.user}") + @Value("${spring.datasource.username}") String user_; @Value("${spring.datasource.password}") From 078f5160727831cd557cd10b7ba6c960430accab Mon Sep 17 00:00:00 2001 From: shinjbin Date: Fri, 16 Dec 2022 04:48:30 +0900 Subject: [PATCH 07/11] init --- .../hotnerds/badgeroad/user/controller/UserController.java | 4 ++-- src/main/resources/application.yml | 3 +++ src/main/resources/data.sql | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/hotnerds/badgeroad/user/controller/UserController.java b/src/main/java/com/hotnerds/badgeroad/user/controller/UserController.java index d4843af..d3ff3b7 100644 --- a/src/main/java/com/hotnerds/badgeroad/user/controller/UserController.java +++ b/src/main/java/com/hotnerds/badgeroad/user/controller/UserController.java @@ -49,8 +49,8 @@ public ResponseEntity getUserInfo(@PathVariable String email) { @GetMapping("/signup") public String showRegistrationForm(Model model){ - MemberDto member = new MemberDto(); - model.addAttribute("member", member); + UserDto user = new UserDto(); + model.addAttribute("user", user); return "signup"; } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 1851d58..fce0d10 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -22,11 +22,14 @@ spring: jpa: database: mysql database-platform: org.hibernate.dialect.MySQL5InnoDBDialect + hibernate: + ddl-auto: create-drop properties: hibernate: show_sql: true format_sql: true use_sql_comments: true + defer-datasource-initialization: true logging: level: diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index 785dd98..ac5bc85 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -1,5 +1,5 @@ insert into user (email, password, nickname) values ('admin', 'admin', 'admin'); -insert into user (username, password, nickname, activated) values ('user', 'user', 'user'); +insert into user (email, password, nickname) values ('user', 'user', 'user'); -- insert into authority (authority_name) values ('ROLE_USER'); -- insert into authority (authority_name) values ('ROLE_ADMIN'); From b196e4c4efc7255d9080ca58f77b7f692b804618 Mon Sep 17 00:00:00 2001 From: shinjbin Date: Fri, 16 Dec 2022 05:01:58 +0900 Subject: [PATCH 08/11] Feat: signup --- .../user/controller/UserController.java | 15 ++------ .../hotnerds/badgeroad/user/dto/UserDto.java | 4 +-- .../hotnerds/badgeroad/user/entity/Badge.java | 4 +++ .../hotnerds/badgeroad/user/entity/User.java | 4 +-- .../badgeroad/user/service/UserService.java | 34 +++++++++---------- src/main/resources/data.sql | 4 +-- 6 files changed, 29 insertions(+), 36 deletions(-) create mode 100644 src/main/java/com/hotnerds/badgeroad/user/entity/Badge.java diff --git a/src/main/java/com/hotnerds/badgeroad/user/controller/UserController.java b/src/main/java/com/hotnerds/badgeroad/user/controller/UserController.java index d3ff3b7..ba92472 100644 --- a/src/main/java/com/hotnerds/badgeroad/user/controller/UserController.java +++ b/src/main/java/com/hotnerds/badgeroad/user/controller/UserController.java @@ -61,19 +61,8 @@ public String showRegistrationForm(Model model){ // handler method to handle register Member form submit request @PostMapping("/signup") - public String registration(@Valid @ModelAttribute("user") UserDto user, - BindingResult result, - Model model){ - UserDto existing = userService.findByEmail(user.getEmail()); - if (existing != null) { - result.rejectValue("email", null, "There is already an account registered with that email"); - } - if (result.hasErrors()) { - model.addAttribute("user", user); - return "signup"; - } - userService.saveUser(userService.userDtoToUser(user)); - return "redirect:/login"; + public ResponseEntity signup(@Valid @RequestBody UserDto userDto){ + return ResponseEntity.ok(userService.signup(userDto)); } @GetMapping("/users") diff --git a/src/main/java/com/hotnerds/badgeroad/user/dto/UserDto.java b/src/main/java/com/hotnerds/badgeroad/user/dto/UserDto.java index 3d698ed..b4bb8f7 100644 --- a/src/main/java/com/hotnerds/badgeroad/user/dto/UserDto.java +++ b/src/main/java/com/hotnerds/badgeroad/user/dto/UserDto.java @@ -26,7 +26,7 @@ public class UserDto { @NotNull @Size(min = 3, max = 50) - private String nickname; + private String name; public static UserDto from(User user) { if(user == null) return null; @@ -34,7 +34,7 @@ public static UserDto from(User user) { return UserDto.builder() .email(user.getEmail()) .password(user.getPassword()) - .nickname(user.getNickname()) + .name(user.getName()) .build(); } } \ No newline at end of file diff --git a/src/main/java/com/hotnerds/badgeroad/user/entity/Badge.java b/src/main/java/com/hotnerds/badgeroad/user/entity/Badge.java new file mode 100644 index 0000000..79b706b --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/user/entity/Badge.java @@ -0,0 +1,4 @@ +package com.hotnerds.badgeroad.user.entity; + +public class Badge { +} diff --git a/src/main/java/com/hotnerds/badgeroad/user/entity/User.java b/src/main/java/com/hotnerds/badgeroad/user/entity/User.java index dc2a092..ea84935 100644 --- a/src/main/java/com/hotnerds/badgeroad/user/entity/User.java +++ b/src/main/java/com/hotnerds/badgeroad/user/entity/User.java @@ -25,7 +25,7 @@ public class User { @Column(name = "password", length = 100) private String password; - @Column(name = "nickname", length = 50) - private String nickname; + @Column(name = "name", length = 50) + private String name; } diff --git a/src/main/java/com/hotnerds/badgeroad/user/service/UserService.java b/src/main/java/com/hotnerds/badgeroad/user/service/UserService.java index 7441c71..d418957 100644 --- a/src/main/java/com/hotnerds/badgeroad/user/service/UserService.java +++ b/src/main/java/com/hotnerds/badgeroad/user/service/UserService.java @@ -9,6 +9,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.Collections; import java.util.List; @@ -16,22 +17,6 @@ @AllArgsConstructor public class UserService { private final UserRepository userRepository; - - @Transactional - public UserDto signup(UserDto userDto) { - if (userRepository.findByEmail(userDto.getEmail()).orElse(null) != null) { - throw new DuplicateMemberException("이미 가입되어 있는 유저입니다."); - } - - User user = User.builder() - .email(userDto.getEmail()) - .password(userDto.getPassword()) - .nickname(userDto.getNickname()) - .build(); - - return UserDto.from(userRepository.save(user)); - } - @Transactional public UserDto findByEmail(String email) { return UserDto.from(userRepository.findByEmail(email).orElse(null)); @@ -41,7 +26,7 @@ public User userDtoToUser(UserDto userDto) { return User.builder() .email(userDto.getEmail()) .password(userDto.getPassword()) - .nickname(userDto.getNickname()) + .name(userDto.getName()) .build(); } @@ -58,4 +43,19 @@ public Boolean loginConfirm(LoginDto loginDto) { UserDto userDto = findByEmail(loginDto.getEmail()); return loginDto.getPassword().equals(userDto.getPassword()); } + + @Transactional + public UserDto signup(UserDto userDto) { + if (userRepository.findByEmail(userDto.getEmail()).orElse(null) != null) { + throw new DuplicateMemberException("이미 가입되어 있는 유저입니다."); + } + + User user = User.builder() + .email(userDto.getEmail()) + .password(userDto.getPassword()) + .name(userDto.getName()) + .build(); + + return UserDto.from(userRepository.save(user)); + } } diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index ac5bc85..741ef7b 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -1,5 +1,5 @@ -insert into user (email, password, nickname) values ('admin', 'admin', 'admin'); -insert into user (email, password, nickname) values ('user', 'user', 'user'); +insert into user (email, password, name) values ('admin', 'admin', 'admin'); +insert into user (email, password, name) values ('user', 'user', 'user'); -- insert into authority (authority_name) values ('ROLE_USER'); -- insert into authority (authority_name) values ('ROLE_ADMIN'); From 6ce69713802c00c783f354827d395022543d9144 Mon Sep 17 00:00:00 2001 From: shinjbin Date: Fri, 16 Dec 2022 05:18:24 +0900 Subject: [PATCH 09/11] feat: login --- .../user/controller/UserController.java | 8 +++++--- .../exception/DuplicateMemberException.java | 16 --------------- .../exception/DuplicateUserException.java | 16 +++++++++++++++ .../exception/NotFoundMemberException.java | 16 --------------- .../user/exception/NotFoundUserException.java | 16 +++++++++++++++ .../badgeroad/user/service/UserService.java | 20 +++++++++++-------- 6 files changed, 49 insertions(+), 43 deletions(-) delete mode 100644 src/main/java/com/hotnerds/badgeroad/user/exception/DuplicateMemberException.java create mode 100644 src/main/java/com/hotnerds/badgeroad/user/exception/DuplicateUserException.java delete mode 100644 src/main/java/com/hotnerds/badgeroad/user/exception/NotFoundMemberException.java create mode 100644 src/main/java/com/hotnerds/badgeroad/user/exception/NotFoundUserException.java diff --git a/src/main/java/com/hotnerds/badgeroad/user/controller/UserController.java b/src/main/java/com/hotnerds/badgeroad/user/controller/UserController.java index ba92472..e6305db 100644 --- a/src/main/java/com/hotnerds/badgeroad/user/controller/UserController.java +++ b/src/main/java/com/hotnerds/badgeroad/user/controller/UserController.java @@ -32,9 +32,11 @@ public String login() { @PostMapping("/login") public String loginConfirm(@Valid @RequestBody LoginDto loginDto) { - userService.loginConfirm(loginDto); - - return "main"; + if (userService.login(loginDto)) { + return "main"; + } else { + return "login"; + } } @GetMapping("/hello") diff --git a/src/main/java/com/hotnerds/badgeroad/user/exception/DuplicateMemberException.java b/src/main/java/com/hotnerds/badgeroad/user/exception/DuplicateMemberException.java deleted file mode 100644 index 26218cc..0000000 --- a/src/main/java/com/hotnerds/badgeroad/user/exception/DuplicateMemberException.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.hotnerds.badgeroad.user.exception; - -public class DuplicateMemberException extends RuntimeException { - public DuplicateMemberException() { - super(); - } - public DuplicateMemberException(String message, Throwable cause) { - super(message, cause); - } - public DuplicateMemberException(String message) { - super(message); - } - public DuplicateMemberException(Throwable cause) { - super(cause); - } -} diff --git a/src/main/java/com/hotnerds/badgeroad/user/exception/DuplicateUserException.java b/src/main/java/com/hotnerds/badgeroad/user/exception/DuplicateUserException.java new file mode 100644 index 0000000..ecc7c55 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/user/exception/DuplicateUserException.java @@ -0,0 +1,16 @@ +package com.hotnerds.badgeroad.user.exception; + +public class DuplicateUserException extends RuntimeException { + public DuplicateUserException() { + super(); + } + public DuplicateUserException(String message, Throwable cause) { + super(message, cause); + } + public DuplicateUserException(String message) { + super(message); + } + public DuplicateUserException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/com/hotnerds/badgeroad/user/exception/NotFoundMemberException.java b/src/main/java/com/hotnerds/badgeroad/user/exception/NotFoundMemberException.java deleted file mode 100644 index 3d7c0a2..0000000 --- a/src/main/java/com/hotnerds/badgeroad/user/exception/NotFoundMemberException.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.hotnerds.badgeroad.user.exception; - -public class NotFoundMemberException extends RuntimeException { - public NotFoundMemberException() { - super(); - } - public NotFoundMemberException(String message, Throwable cause) { - super(message, cause); - } - public NotFoundMemberException(String message) { - super(message); - } - public NotFoundMemberException(Throwable cause) { - super(cause); - } -} diff --git a/src/main/java/com/hotnerds/badgeroad/user/exception/NotFoundUserException.java b/src/main/java/com/hotnerds/badgeroad/user/exception/NotFoundUserException.java new file mode 100644 index 0000000..7def7aa --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/user/exception/NotFoundUserException.java @@ -0,0 +1,16 @@ +package com.hotnerds.badgeroad.user.exception; + +public class NotFoundUserException extends RuntimeException { + public NotFoundUserException() { + super(); + } + public NotFoundUserException(String message, Throwable cause) { + super(message, cause); + } + public NotFoundUserException(String message) { + super(message); + } + public NotFoundUserException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/com/hotnerds/badgeroad/user/service/UserService.java b/src/main/java/com/hotnerds/badgeroad/user/service/UserService.java index d418957..7e0274b 100644 --- a/src/main/java/com/hotnerds/badgeroad/user/service/UserService.java +++ b/src/main/java/com/hotnerds/badgeroad/user/service/UserService.java @@ -3,7 +3,8 @@ import com.hotnerds.badgeroad.user.dto.LoginDto; import com.hotnerds.badgeroad.user.dto.UserDto; import com.hotnerds.badgeroad.user.entity.User; -import com.hotnerds.badgeroad.user.exception.DuplicateMemberException; +import com.hotnerds.badgeroad.user.exception.DuplicateUserException; +import com.hotnerds.badgeroad.user.exception.NotFoundUserException; import com.hotnerds.badgeroad.user.repository.UserRepository; import lombok.AllArgsConstructor; import org.springframework.stereotype.Service; @@ -11,6 +12,7 @@ import java.util.Collections; import java.util.List; +import java.util.Optional; @Service @@ -38,16 +40,10 @@ public List findAllUsers() { return userRepository.findAll(); } - public Boolean loginConfirm(LoginDto loginDto) { - - UserDto userDto = findByEmail(loginDto.getEmail()); - return loginDto.getPassword().equals(userDto.getPassword()); - } - @Transactional public UserDto signup(UserDto userDto) { if (userRepository.findByEmail(userDto.getEmail()).orElse(null) != null) { - throw new DuplicateMemberException("이미 가입되어 있는 유저입니다."); + throw new DuplicateUserException("이미 가입되어 있는 유저입니다."); } User user = User.builder() @@ -58,4 +54,12 @@ public UserDto signup(UserDto userDto) { return UserDto.from(userRepository.save(user)); } + + public Boolean login(LoginDto loginDto) { + Optional user = userRepository.findByEmail(loginDto.getEmail()); + + return user.map(value -> value.getPassword().equals(loginDto.getPassword())).orElse(false); + + + } } From e51f5abc0bbb8a82a0b4cdda40f2e3ed9ae59e50 Mon Sep 17 00:00:00 2001 From: shinjbin Date: Fri, 16 Dec 2022 06:07:49 +0900 Subject: [PATCH 10/11] feat: badge entity --- .../user/controller/UserController.java | 5 ---- .../hotnerds/badgeroad/user/dto/BadgeDto.java | 15 +++++++++++ .../hotnerds/badgeroad/user/dto/LoginDto.java | 2 ++ .../badgeroad/user/dto/MemberDto.java | 25 ------------------- .../badgeroad/user/dto/MemberLoginDto.java | 11 -------- .../hotnerds/badgeroad/user/dto/UserDto.java | 2 ++ .../hotnerds/badgeroad/user/entity/Badge.java | 25 +++++++++++++++++++ .../hotnerds/badgeroad/user/entity/User.java | 16 ++++++++++++ .../user/repository/BadgeRepository.java | 11 ++++++++ .../user/repository/UserRepository.java | 5 ++++ .../badgeroad/user/service/BadgeService.java | 25 +++++++++++++++++++ .../badgeroad/user/service/UserService.java | 24 +++++++++++++++--- src/main/resources/data.sql | 4 +-- 13 files changed, 124 insertions(+), 46 deletions(-) create mode 100644 src/main/java/com/hotnerds/badgeroad/user/dto/BadgeDto.java delete mode 100644 src/main/java/com/hotnerds/badgeroad/user/dto/MemberDto.java delete mode 100644 src/main/java/com/hotnerds/badgeroad/user/dto/MemberLoginDto.java create mode 100644 src/main/java/com/hotnerds/badgeroad/user/repository/BadgeRepository.java create mode 100644 src/main/java/com/hotnerds/badgeroad/user/service/BadgeService.java diff --git a/src/main/java/com/hotnerds/badgeroad/user/controller/UserController.java b/src/main/java/com/hotnerds/badgeroad/user/controller/UserController.java index e6305db..605ad60 100644 --- a/src/main/java/com/hotnerds/badgeroad/user/controller/UserController.java +++ b/src/main/java/com/hotnerds/badgeroad/user/controller/UserController.java @@ -1,19 +1,14 @@ package com.hotnerds.badgeroad.user.controller; import com.hotnerds.badgeroad.user.dto.LoginDto; -import com.hotnerds.badgeroad.user.dto.MemberDto; import com.hotnerds.badgeroad.user.dto.UserDto; import com.hotnerds.badgeroad.user.entity.User; import com.hotnerds.badgeroad.user.service.UserService; import org.springframework.http.ResponseEntity; import org.springframework.ui.Model; -import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.*; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; -import java.io.IOException; import java.util.List; @RestController diff --git a/src/main/java/com/hotnerds/badgeroad/user/dto/BadgeDto.java b/src/main/java/com/hotnerds/badgeroad/user/dto/BadgeDto.java new file mode 100644 index 0000000..aae45e5 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/user/dto/BadgeDto.java @@ -0,0 +1,15 @@ +package com.hotnerds.badgeroad.user.dto; + +import javax.validation.constraints.NotNull; + +public class BadgeDto { + + @NotNull + private String name; + + @NotNull + private String location; + + @NotNull + private String category; +} diff --git a/src/main/java/com/hotnerds/badgeroad/user/dto/LoginDto.java b/src/main/java/com/hotnerds/badgeroad/user/dto/LoginDto.java index c2aabeb..9760d77 100644 --- a/src/main/java/com/hotnerds/badgeroad/user/dto/LoginDto.java +++ b/src/main/java/com/hotnerds/badgeroad/user/dto/LoginDto.java @@ -2,6 +2,7 @@ import lombok.*; +import javax.validation.constraints.Email; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; @@ -14,6 +15,7 @@ public class LoginDto { @NotNull @Size(min = 3, max = 50) + @Email private String email; @NotNull diff --git a/src/main/java/com/hotnerds/badgeroad/user/dto/MemberDto.java b/src/main/java/com/hotnerds/badgeroad/user/dto/MemberDto.java deleted file mode 100644 index b366163..0000000 --- a/src/main/java/com/hotnerds/badgeroad/user/dto/MemberDto.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.hotnerds.badgeroad.user.dto; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import javax.validation.constraints.Email; -import javax.validation.constraints.NotEmpty; - -@Getter -@Setter -@NoArgsConstructor -@AllArgsConstructor -public class MemberDto -{ - private Long id; - @NotEmpty(message = "Email should not be empty") - @Email - private String email; - @NotEmpty(message = "Password should not be empty") - private String password; - @NotEmpty(message = "name should not be empty") - private String name; -} \ No newline at end of file diff --git a/src/main/java/com/hotnerds/badgeroad/user/dto/MemberLoginDto.java b/src/main/java/com/hotnerds/badgeroad/user/dto/MemberLoginDto.java deleted file mode 100644 index dd84c77..0000000 --- a/src/main/java/com/hotnerds/badgeroad/user/dto/MemberLoginDto.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.hotnerds.badgeroad.user.dto; - -import lombok.Getter; -import lombok.Setter; - -@Getter -@Setter -public class MemberLoginDto { - private String email; - private String password; -} diff --git a/src/main/java/com/hotnerds/badgeroad/user/dto/UserDto.java b/src/main/java/com/hotnerds/badgeroad/user/dto/UserDto.java index b4bb8f7..afbbddc 100644 --- a/src/main/java/com/hotnerds/badgeroad/user/dto/UserDto.java +++ b/src/main/java/com/hotnerds/badgeroad/user/dto/UserDto.java @@ -5,6 +5,7 @@ import lombok.*; import javax.persistence.Id; +import javax.validation.constraints.Email; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import java.util.stream.Collectors; @@ -18,6 +19,7 @@ public class UserDto { @NotNull @Size(min = 3, max = 50) + @Email private String email; @NotNull diff --git a/src/main/java/com/hotnerds/badgeroad/user/entity/Badge.java b/src/main/java/com/hotnerds/badgeroad/user/entity/Badge.java index 79b706b..298712b 100644 --- a/src/main/java/com/hotnerds/badgeroad/user/entity/Badge.java +++ b/src/main/java/com/hotnerds/badgeroad/user/entity/Badge.java @@ -1,4 +1,29 @@ package com.hotnerds.badgeroad.user.entity; +import lombok.*; + +import javax.persistence.*; + +@Entity +@Table(name = "badge") +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor public class Badge { + + @Id + @Column(name = "badge_id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long badgeId; + + @Column(name = "name", length = 50, unique = true) + private String name; + + @Column(name = "location", length = 10) + private String location; + + @Column(name = "category", length = 20) + private String category; } diff --git a/src/main/java/com/hotnerds/badgeroad/user/entity/User.java b/src/main/java/com/hotnerds/badgeroad/user/entity/User.java index ea84935..3a34d9b 100644 --- a/src/main/java/com/hotnerds/badgeroad/user/entity/User.java +++ b/src/main/java/com/hotnerds/badgeroad/user/entity/User.java @@ -1,8 +1,11 @@ package com.hotnerds.badgeroad.user.entity; import lombok.*; +import org.hibernate.annotations.ColumnDefault; +import org.hibernate.annotations.DynamicInsert; import javax.persistence.*; +import javax.validation.constraints.Email; import java.util.Set; @Entity @@ -12,6 +15,7 @@ @Builder @AllArgsConstructor @NoArgsConstructor +@DynamicInsert public class User { @Id @@ -20,6 +24,7 @@ public class User { private Long userId; @Column(name = "email", length = 50, unique = true) + @Email private String email; @Column(name = "password", length = 100) @@ -28,4 +33,15 @@ public class User { @Column(name = "name", length = 50) private String name; + @Column(name = "level") + @ColumnDefault("1") + private Integer level; + + @OneToMany + @JoinTable( + name = "user_badges", + joinColumns = {@JoinColumn(name = "email", referencedColumnName = "email")}, + inverseJoinColumns = {@JoinColumn(name = "badge_name", referencedColumnName = "name")} + ) + private Set badges; } diff --git a/src/main/java/com/hotnerds/badgeroad/user/repository/BadgeRepository.java b/src/main/java/com/hotnerds/badgeroad/user/repository/BadgeRepository.java new file mode 100644 index 0000000..2319b1b --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/user/repository/BadgeRepository.java @@ -0,0 +1,11 @@ +package com.hotnerds.badgeroad.user.repository; + +import com.hotnerds.badgeroad.user.entity.Badge; +import org.springframework.data.jpa.repository.JpaRepository; + + +import java.util.Optional; + +public interface BadgeRepository extends JpaRepository { + Optional findByName(String name); +} diff --git a/src/main/java/com/hotnerds/badgeroad/user/repository/UserRepository.java b/src/main/java/com/hotnerds/badgeroad/user/repository/UserRepository.java index c745313..1dae4ef 100644 --- a/src/main/java/com/hotnerds/badgeroad/user/repository/UserRepository.java +++ b/src/main/java/com/hotnerds/badgeroad/user/repository/UserRepository.java @@ -1,11 +1,16 @@ package com.hotnerds.badgeroad.user.repository; +import com.hotnerds.badgeroad.user.entity.Badge; import com.hotnerds.badgeroad.user.entity.User; import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.List; import java.util.Optional; public interface UserRepository extends JpaRepository { Optional findByEmail(String email); + + @EntityGraph(attributePaths = "badge") + List findAllBadgesByEmail(String email); } diff --git a/src/main/java/com/hotnerds/badgeroad/user/service/BadgeService.java b/src/main/java/com/hotnerds/badgeroad/user/service/BadgeService.java new file mode 100644 index 0000000..e60402b --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/user/service/BadgeService.java @@ -0,0 +1,25 @@ +package com.hotnerds.badgeroad.user.service; + +import com.hotnerds.badgeroad.user.entity.Badge; +import com.hotnerds.badgeroad.user.repository.BadgeRepository; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; + +@Service +@AllArgsConstructor +public class BadgeService { + + BadgeRepository badgeRepository; + + public Optional findByName(String name) { + return badgeRepository.findByName(name); + } + + public List findAllBadges() { + return badgeRepository.findAll(); + } + +} diff --git a/src/main/java/com/hotnerds/badgeroad/user/service/UserService.java b/src/main/java/com/hotnerds/badgeroad/user/service/UserService.java index 7e0274b..673feba 100644 --- a/src/main/java/com/hotnerds/badgeroad/user/service/UserService.java +++ b/src/main/java/com/hotnerds/badgeroad/user/service/UserService.java @@ -2,23 +2,26 @@ import com.hotnerds.badgeroad.user.dto.LoginDto; import com.hotnerds.badgeroad.user.dto.UserDto; +import com.hotnerds.badgeroad.user.entity.Badge; import com.hotnerds.badgeroad.user.entity.User; import com.hotnerds.badgeroad.user.exception.DuplicateUserException; import com.hotnerds.badgeroad.user.exception.NotFoundUserException; import com.hotnerds.badgeroad.user.repository.UserRepository; import lombok.AllArgsConstructor; +import org.apache.catalina.mapper.Mapper; +import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.Collections; -import java.util.List; -import java.util.Optional; +import java.util.*; @Service @AllArgsConstructor public class UserService { private final UserRepository userRepository; + + private final JdbcTemplate jdbcTemplate; @Transactional public UserDto findByEmail(String email) { return UserDto.from(userRepository.findByEmail(email).orElse(null)); @@ -62,4 +65,19 @@ public Boolean login(LoginDto loginDto) { } + +// public List findAllBadgesByEmail(String email) { +// Map params = new HashMap<>(); +// params.put("email", email); +// Optional user = userRepository.findByEmail(email); +// +// return jdbcTemplate.queryForList( +// "SELECT " + +// "badge_name" + +// "FROM " + +// "user_badges" + +// "WHERE " + +// "email = :email", params); +// ) +// } } diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index 741ef7b..781ceda 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -1,5 +1,5 @@ -insert into user (email, password, name) values ('admin', 'admin', 'admin'); -insert into user (email, password, name) values ('user', 'user', 'user'); +insert into user (email, password, name) values ('admin@admin.com', 'admin', 'admin'); +insert into user (email, password, name) values ('user@user.com', 'user', 'user'); -- insert into authority (authority_name) values ('ROLE_USER'); -- insert into authority (authority_name) values ('ROLE_ADMIN'); From 12ca7c09e0bd9b71a099967527355a7eb0106084 Mon Sep 17 00:00:00 2001 From: shinjbin Date: Sun, 18 Dec 2022 22:29:04 +0900 Subject: [PATCH 11/11] feat: add store entity --- .../store/controller/StoreController.java | 4 ++ .../badgeroad/store/entity/Store.java | 64 +++++++++++++++++++ .../store/repository/StoreRepository.java | 16 +++++ .../badgeroad/store/service/StoreService.java | 16 +++++ .../badgeroad/user/service/BadgeService.java | 5 ++ src/main/resources/application.yml | 4 +- src/main/resources/{ => sql}/data.sql | 4 +- 7 files changed, 109 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/hotnerds/badgeroad/store/controller/StoreController.java create mode 100644 src/main/java/com/hotnerds/badgeroad/store/entity/Store.java create mode 100644 src/main/java/com/hotnerds/badgeroad/store/repository/StoreRepository.java create mode 100644 src/main/java/com/hotnerds/badgeroad/store/service/StoreService.java rename src/main/resources/{ => sql}/data.sql (68%) diff --git a/src/main/java/com/hotnerds/badgeroad/store/controller/StoreController.java b/src/main/java/com/hotnerds/badgeroad/store/controller/StoreController.java new file mode 100644 index 0000000..2d92dc4 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/store/controller/StoreController.java @@ -0,0 +1,4 @@ +package com.hotnerds.badgeroad.store.controller; + +public class StoreController { +} diff --git a/src/main/java/com/hotnerds/badgeroad/store/entity/Store.java b/src/main/java/com/hotnerds/badgeroad/store/entity/Store.java new file mode 100644 index 0000000..98aaafa --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/store/entity/Store.java @@ -0,0 +1,64 @@ +package com.hotnerds.badgeroad.store.entity; + +import lombok.*; +import org.hibernate.annotations.ColumnDefault; +import org.hibernate.annotations.DynamicInsert; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name = "store") +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor +@DynamicInsert +public class Store { + + @Id + private Long management_number; + + @Column + private String store_name; + + @Column + private String location_code; + + @Column + private Integer category_code; + + @Column + private String category_name; + + @Column + private Integer industry_code; + + @Column + private String industry_name; + + @Column + private Integer food_authentication_num; + + @Column + private String food_authentication_name; + + @Column + private Double map_y; + + @Column + private Double map_x; + + @Column + private String phone_number; + + @Column + private String address; + + @Column + @ColumnDefault("0") + private Integer liked; +} diff --git a/src/main/java/com/hotnerds/badgeroad/store/repository/StoreRepository.java b/src/main/java/com/hotnerds/badgeroad/store/repository/StoreRepository.java new file mode 100644 index 0000000..e26a9b6 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/store/repository/StoreRepository.java @@ -0,0 +1,16 @@ +package com.hotnerds.badgeroad.store.repository; + +import com.hotnerds.badgeroad.store.entity.Store; +import com.hotnerds.badgeroad.user.entity.Badge; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; +import javax.persistence.PersistenceContext; +import java.util.List; + +public interface StoreRepository extends JpaRepository { + +} diff --git a/src/main/java/com/hotnerds/badgeroad/store/service/StoreService.java b/src/main/java/com/hotnerds/badgeroad/store/service/StoreService.java new file mode 100644 index 0000000..e6598f4 --- /dev/null +++ b/src/main/java/com/hotnerds/badgeroad/store/service/StoreService.java @@ -0,0 +1,16 @@ +package com.hotnerds.badgeroad.store.service; + +import com.hotnerds.badgeroad.store.entity.Store; +import com.hotnerds.badgeroad.store.repository.StoreRepository; +import com.hotnerds.badgeroad.user.entity.Role; +import lombok.AllArgsConstructor; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@AllArgsConstructor +public class StoreService { + private final StoreRepository storeRepository; +} diff --git a/src/main/java/com/hotnerds/badgeroad/user/service/BadgeService.java b/src/main/java/com/hotnerds/badgeroad/user/service/BadgeService.java index e60402b..6175897 100644 --- a/src/main/java/com/hotnerds/badgeroad/user/service/BadgeService.java +++ b/src/main/java/com/hotnerds/badgeroad/user/service/BadgeService.java @@ -1,5 +1,6 @@ package com.hotnerds.badgeroad.user.service; +import com.hotnerds.badgeroad.store.repository.StoreRepository; import com.hotnerds.badgeroad.user.entity.Badge; import com.hotnerds.badgeroad.user.repository.BadgeRepository; import lombok.AllArgsConstructor; @@ -22,4 +23,8 @@ public List findAllBadges() { return badgeRepository.findAll(); } + public void putAllBadgesFromStore() { +// StoreRepository + } + } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index fce0d10..f271321 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -22,8 +22,8 @@ spring: jpa: database: mysql database-platform: org.hibernate.dialect.MySQL5InnoDBDialect - hibernate: - ddl-auto: create-drop +# hibernate: +# ddl-auto: create properties: hibernate: show_sql: true diff --git a/src/main/resources/data.sql b/src/main/resources/sql/data.sql similarity index 68% rename from src/main/resources/data.sql rename to src/main/resources/sql/data.sql index 781ceda..f5cf19b 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/sql/data.sql @@ -1,5 +1,5 @@ -insert into user (email, password, name) values ('admin@admin.com', 'admin', 'admin'); -insert into user (email, password, name) values ('user@user.com', 'user', 'user'); +-- insert into user (email, password, name) values ('admin@admin.com', 'admin', 'admin'); +-- insert into user (email, password, name) values ('user@user.com', 'user', 'user'); -- insert into authority (authority_name) values ('ROLE_USER'); -- insert into authority (authority_name) values ('ROLE_ADMIN');