Skip to content

Commit

Permalink
Feat: making login (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
hejin8307 committed May 2, 2024
1 parent 53c3388 commit 2287192
Show file tree
Hide file tree
Showing 17 changed files with 336 additions and 50 deletions.
5 changes: 5 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ repositories {
}

dependencies {
//Jwt
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
implementation 'io.jsonwebtoken:jjwt-impl:0.11.5'
implementation 'io.jsonwebtoken:jjwt-jackson:0.11.5'

implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.hanaro.starbucks.config;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.GenericFilterBean;

import java.io.IOException;

@RequiredArgsConstructor
public class JwtAuthenticationFilter extends GenericFilterBean {

private final JwtUtil jwtTokenProvider;

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String token = jwtTokenProvider.resolveToken((HttpServletRequest) request);

if (token != null && jwtTokenProvider.validateToken(token)) {
Authentication authentication = jwtTokenProvider.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
filterChain.doFilter(request, response);
}
}
72 changes: 72 additions & 0 deletions src/main/java/com/hanaro/starbucks/config/JwtUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package com.hanaro.starbucks.config;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import jakarta.annotation.PostConstruct;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;

import java.util.Base64;
import java.util.Date;
import java.util.List;

@Component
@RequiredArgsConstructor
public class JwtUtil {
@Value("${jwt.secretKey}")
private String secretKey;

@Value("${jwt.expiration_time}")
private long expireTime;

private final UserDetailsService userDetailsService;

@PostConstruct
protected void init() {
secretKey = Base64.getEncoder().encodeToString(secretKey.getBytes());
}

public String createToken(String userId, List<String> roleList) {
Claims claims = Jwts.claims().setSubject(userId);
claims.put("roles", roleList);
Date now = new Date();
return Jwts.builder()
.setClaims(claims)
.setIssuedAt(now)
.setExpiration(new Date(now.getTime() + expireTime))
.signWith(SignatureAlgorithm.HS256, secretKey)
.compact();
}

public Authentication getAuthentication(String token) {
String userId = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody().getSubject();
UserDetails userDetails = userDetailsService.loadUserByUsername(userId);
return new UsernamePasswordAuthenticationToken(
userDetails, "", userDetails.getAuthorities()
);
}

public String resolveToken(HttpServletRequest request) {
return request.getHeader("X-AUTH-TOKEN");
}

public boolean validateToken(String token){
try{
Jws<Claims> claims = Jwts.parser().setSigningKey(secretKey)
.parseClaimsJws(token);
return claims.getBody().getExpiration().before(new Date()) == false;
}
catch (Exception e){
return false;
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.hanaro.starbucks.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@Configuration
public class PasswordEncoderConfig {
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}
71 changes: 71 additions & 0 deletions src/main/java/com/hanaro/starbucks/config/SecurityConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package com.hanaro.starbucks.config;

import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.Collections;

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
private final JwtUtil jwtConfig;

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf((auth) -> auth.disable())
.cors((cors) -> cors.configurationSource(corsConfigurationSource()))

.authorizeHttpRequests((auth) -> auth
// 로그인과 회원가입은 모든 사용자에게 허용한다.
.requestMatchers(
new AntPathRequestMatcher("/login"),
new AntPathRequestMatcher("/signup")
).permitAll() // 권한이 있든 말든 모두 접근 가능
// admin일 경우에만 /admin에 대한 요청에서 접근을 허용한다.
.requestMatchers("/admin").hasRole("ADMIN")
// 그 외 모든 요청은 인증된 사용자에게만 허용한다.
.anyRequest().authenticated()
)
.sessionManagement(sessionManagement ->
sessionManagement.sessionCreationPolicy(
SessionCreationPolicy.STATELESS
))
.addFilterBefore(new JwtAuthenticationFilter(jwtConfig),
UsernamePasswordAuthenticationFilter.class);
// .formLogin((formLogin) -> formLogin
// .loginProcessingUrl("/login")
// .successHandler(((request, response, authentication) -> {
// System.out.println("로그인 성공했습니다.");
// response.sendRedirect("/");
// }))
// .permitAll()
// );

return http.build();
}

@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedHeaders(Collections.singletonList("*")); // 허용할 HTTP header
config.setAllowedMethods(Collections.singletonList("*")); // 허용할 HTTP method
config.setAllowedOriginPatterns(Collections.singletonList("http://localhost:5173")); // 허용할 출처
config.setAllowCredentials(true); // 쿠키 인증 요청 허용

UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.hanaro.starbucks.controller;

import com.hanaro.starbucks.config.JwtUtil;
import com.hanaro.starbucks.dto.user.LoginReqDto;
import com.hanaro.starbucks.dto.user.MemberResDto;
import com.hanaro.starbucks.service.MemberService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

import java.util.Arrays;
import java.util.List;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/users")
public class MemberController {
private final MemberService userService;
private final JwtUtil jwtUtil;

@GetMapping("")
public List<MemberResDto> getUsers(){
return userService.getUsers();
}

@PostMapping("/login")
public String login(@RequestParam LoginReqDto user) {
MemberResDto findUser = userService.findUser(user.getUserId(), user.getUserPw());

return jwtUtil.createToken(findUser.getUserId(), Arrays.asList(findUser.getUserRole()));
}

}
22 changes: 0 additions & 22 deletions src/main/java/com/hanaro/starbucks/controller/UserController.java

This file was deleted.

12 changes: 12 additions & 0 deletions src/main/java/com/hanaro/starbucks/dto/user/LoginReqDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.hanaro.starbucks.dto.user;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
@AllArgsConstructor
public class LoginReqDto {
private String userId, userPw;
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package com.hanaro.starbucks.dto.user;

import com.hanaro.starbucks.entity.User;
import com.hanaro.starbucks.entity.Member;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.time.LocalDate;

@Getter
public class UserResDto {
@NoArgsConstructor
public class MemberResDto {
private int userIdx;

private String userId;
Expand All @@ -21,7 +24,7 @@ public class UserResDto {

private LocalDate userJoinDate;

public UserResDto(User user){
public MemberResDto(Member user){
this.userIdx = user.getUserIdx();
this.userId = user.getUserId();
this.userPw = user.getUserPw();
Expand Down
17 changes: 17 additions & 0 deletions src/main/java/com/hanaro/starbucks/dto/user/SignupReqDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.hanaro.starbucks.dto.user;

import jakarta.validation.constraints.NotBlank;
import lombok.*;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class SignupReqDto {
@NotBlank(message = "아이디는 필수 입력 값입니다.")
private String userId;
@NotBlank(message = "비밀번호는 필수 입력 값입니다.")
private String userPw;
@NotBlank(message = "닉네임은 필수 입력 값입니다.")
private String userNickname;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.hanaro.starbucks.entity;

import com.hanaro.starbucks.dto.user.MemberResDto;
import jakarta.persistence.*;
import lombok.Getter;

Expand All @@ -8,7 +9,7 @@
@Entity
@Getter
@Table(name = "user")
public class User {
public class Member {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Expand All @@ -32,5 +33,4 @@ public class User {

@Column(name = "user_join_date")
private LocalDate userJoinDate;

}
2 changes: 1 addition & 1 deletion src/main/java/com/hanaro/starbucks/entity/Orders.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public class Orders {

@ManyToOne
@JoinColumn(name = "user_idx")
private User user;
private Member user;

@OneToMany(mappedBy = "orders", cascade = CascadeType.ALL)
private List<OrderDetail> orderDetails;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
package com.hanaro.starbucks.repository;

import com.hanaro.starbucks.entity.User;
import com.hanaro.starbucks.entity.Member;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Optional;

@Repository
public interface UserRepository extends JpaRepository<User, Integer> {
public interface UserRepository extends JpaRepository<Member, Integer> {
List<Member> findByUserId(String userId);

Optional<Member> findByUserIdAndUserPw(String userId, String userPw);
}
27 changes: 27 additions & 0 deletions src/main/java/com/hanaro/starbucks/service/MemberService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.hanaro.starbucks.service;

import com.hanaro.starbucks.dto.user.MemberResDto;
import com.hanaro.starbucks.entity.Member;
import com.hanaro.starbucks.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class MemberService {
private final UserRepository userRepository;

public List<MemberResDto> getUsers(){
return userRepository.findAll().stream().map(MemberResDto::new).collect(Collectors.toList());
}

public MemberResDto findUser(String userId, String userPw) {
Optional<Member> optional = userRepository.findByUserIdAndUserPw(userId, userPw);

return optional.map(MemberResDto::new).orElseGet(MemberResDto::new);
}
}
Loading

0 comments on commit 2287192

Please sign in to comment.