2023.08.02.수.TIL

heeh·2023년 8월 2일

TIL

목록 보기
56/82
post-thumbnail

2023.08.02.수.TIL

  • 역할
    1. Oauth2.0을 이용한 소셜로그인 (ㅊㅈㅇ님)
    2. 팔로우, 팔로워, 좋아요 기능 (ㄱㄷㅎ님)
    3. 게시글, 댓글 CRUD (ㅇㄴㅁ님)
    4. Security (ㄱㅈㅎ님)
    5. 프로필 기능 (ㅂㄱㅎ님)
  • https://github.com/alxqkekrroqkfwk/Hybrid
  • 드디어 security
  • security 순서??
  • user entity → controller → service → repository 먼저 만들고 security, config, jwt를 생성?!
    • user entity → security, config, jwt
    • controller → service → repository 는 로그인, 회원가입 관련

물어보기

  • build.gradle
    dependencies {
        // JWT
        compileOnly group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.11.5'
        runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.5'
        runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.5'
    
        // json
        implementation 'org.json:json:20230227'
    
        implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
        implementation 'org.springframework.boot:spring-boot-starter-security'
        implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
        implementation 'org.springframework.boot:spring-boot-starter-validation'
        implementation 'org.springframework.boot:spring-boot-starter-web'
        implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6'
        compileOnly 'org.projectlombok:lombok'
        runtimeOnly 'com.mysql:mysql-connector-j'
        annotationProcessor 'org.projectlombok:lombok'
        testImplementation 'org.springframework.boot:spring-boot-starter-test'
        testImplementation 'org.springframework.security:spring-security-test'
    }
  • JwtAuthenticationFilter 로그인 역할
    • 원래 @RequiredArgsConstructor 쓰는 것은 지양
    • @RequiredArgsConstructor 없으면
      private final JwtUtil jwtUtil;
      
          public JwtAuthenticationFilter(JwtUtil jwtUtil) {
              this.jwtUtil = jwtUtil;
          }
  • JwtAuthenticationFilter가 있는데 UserController에 @PostMapping("/login") 없어도 된닷?
    • UserController에서 로그인 해주는 것이 아닌JwtAuthenticationFilter에서 로그인을 처리해줘야 한다!
      • setFilterProcessesUrl(”/api/user/login”);
  • JwtAuthorizationFilter
    • JwtAuthenticationFilter의(로그인을 하면) 쿠키나 헤더에 담긴 토큰에 대해 유효성 검사
    • UserDetailsImpl과 UserDetailsServiceImpl을 완성시켜줌
  • JwtAuthenticationFilter(로그인)을 하고 JwtAuthorizationFilter(검사)가 이루어지고 UserDetailsImpl, UserDetailsServiceImpl(로그인 한 유저 정보)가 담긴다
  • 전체적인 설정은 WebSecurityConfig
  • 로그인에 필요한 기능을 설정
    http.authorizeHttpRequests((authorizeHttpRequests) ->
                    authorizeHttpRequests
                            .requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll() // resources 접근 허용 설정
                            .requestMatchers("/api/signup").permitAll()
                            .requestMatchers("/api/**").permitAll()//
                            .anyRequest().authenticated() // 그 외 모든 요청 인증처리
            );
    • .requestMatchers("/api/signup").permitAll() : 회원가입은 로그인 정보가 필요하지 않다!
    • .requestMatchers("/api/**").permitAll() : api 뒤에 어떤 상세 링크가 모든 로그인이 필요하지 않다!
    • .requestMatchers("/api/signup").permitAll()는 .requestMatchers("/api/**").permitAll()에 포함
  • 왜 Entity에 nullable = false,unique = true 를 지정해 주는가?
    • controller에서 해도 되고 service에서 해도 되지만 코드가 유실될 수도!
    • 그래서 Entity를 만들어 줄 때 성질을 아예 만들어주기!
    • JPA가 Entity를 원해?!
      • public interface UserRepository extends JpaRepository<User,Long>
        → JpaRepository는 Entity User를 필요로 함
  • UserDetailsServiceImpl 는 뭔가?
  • http.폼로그인? - 로그인은 이것으로 하겠다!, 로그인이 필요할 때 가는..곳..?

팀장님 Security

JwtUtil

  • public String createToken(String username)
    • username을 String 으로 가져옴
  • BEARER_PREFIX BEARER를 붙여주는 것은 약속
  • .setExpiration(new Date(date.getTime() + TOKEN_TIME))
    • date.getTime() : 만들어진 시간(순간)부터 + 토큰 유지 시간
  • Cookie cookie = new Cookie(AUTHORIZATION_HEADER, token); // Name-Value
    • Name : AUTHORIZATION_HEADER
    • Value : token
  • HttpServletResponse가 헤더는 아니지만 헤더에 담기게 하려면 필요..?!
  • 순수한 토큰을 얻기 위해 앞에 붙은 BEARER 6글자와 띄어쓰기 1글자 포함 총 7글자를 제거 해줘야 함
    // JWT 토큰 substring
        public String substringToken(String tokenValue) {
            if (StringUtils.hasText(tokenValue) && tokenValue.startsWith(BEARER_PREFIX)) {
                return tokenValue.substring(7);
            }
            logger.error("Not Found Token");
            throw new NullPointerException("Not Found Token");
        }
  • 토큰을 넣으면 Claims 타입으로 변함
    • Claims 메서드를 쓰는 ?
  • public String getTokenFromRequest(HttpServletRequest req)
    • Cookie[] cookies = req.getCookies();
      • 쿠키 배열에 HttpServletResponse의 쿠키를 넣어준다
    • if (cookies != null)
      • 쿠키에 값이 있다면
    • for (Cookie cookie : cookies)
      • 쿠키를 하나하나 뽑늗다?!
    • if (cookie.getName().equals(AUTHORIZATION_HEADER))
      • 추가해준 쿠키의 이름과 AUTHORIZATION_HEADER가 같다면?
    • return URLDecoder.decode
      • 문자가 이상하게 encode 될 때를 대비?!

JwtAuthenticationFilter

  • getAuthenticationManager().authenticate()
    • getAuthenticationManager() : Manager가 토큰을 만듦
    • .authenticate() : 대조
  • .authenticate() : 대조를 왜 해줘야 하는가?
    • getAuthenticationManager()와 new UsernamePasswordAuthenticationToken 대조!
    • new UsernamePasswordAuthenticationToken에 requestDto.getUserName(), requestDto.getUserPassword(), null가 있음 = 사용자가 입력한 값!
    • getAuthenticationManager()는 UserDetailsServiceImpl로 UserRepository를 받아 오고 있다
    • Manager가 내부 로직을 통해서 UserDetailsServiceImpl와 연결?! 연관?!
  • 가장 처음에 시작되는 것이 Filter
  • Manager가 Security 기능

  • null???
    return getAuthenticationManager().authenticate(
                        new UsernamePasswordAuthenticationToken(
                                requestDto.getUserName(),
                                requestDto.getUserPassword(),
                                null
                        )
                );
    • 유저의 권한 값을 넣어줌
    • 유저의 권한이 일반 유저인지, 관리자인지!

JwtAuthorizationFilter

  • String tokenValue = jwtUtil.getTokenFromRequest(req);
    • public String getTokenFromRequest(HttpServletRequest req)를 통해 내가 만든 토큰만 tokenValue에 담김
  • UsernamePasswordAuthenticationToken = Authentication

WebSecurityConfig

  • http에 필터를 추가 해주는!
    // 필터 관리
    http.addFilterBefore(jwtAuthorizationFilter(), JwtAuthenticationFilter.class);
    http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
    • 필터 먼저 실행
  • .anyRequest().authenticated()
    • 인증 처리 필요

  • JwtUtil은 토큰 공장
  • // 사용자 권한 값의 KEYpublic static final String AUTHORIZATION_KEY = "auth";

Security 하기

  • 유저 네임 중복 금지하기
    UserService
    
    Optional<User> checkUsername = userRepository.findByUserName(userName);
            if (checkUsername.isPresent()) { //isPresent() --> 데이터에 동일 데이터가 있는지 확인.
                throw new IllegalArgumentException("중복된 사용자가 존재합니다.");
            }
    UserRepository
    
    Optional<User> findByUserName(String userName);
  • 이메일 중복 금지하기
    UserService
    
    Optional<User> checkEmail = userRepository.findByUserEmail(userEmail);
            if (checkEmail.isPresent()) {
                throw new IllegalArgumentException("중복된 Email 입니다.");
            }
    UserRepository
    
    Optional<User> findByUserEmail(String email);
  • feature/이슈번호/{기능 설명}
  • 커밋 → 푸시 → 풀리퀘스트 → 이슈 클로즈 → 머지 확인(팀장님) → 이슈 만들기 → remote - 디벨롭 체크아웃 → local 디벨롭 업데이트 → 디벨롭 기준으로 브랜츠 따서 feature/이슈번호/{기능 설명} → 기능 구현 → 반복
  • 필터-로그인 부분 클래스 오류나는 것 수정 - 커밋까지 함!
  • UserController
    • 예외 처리로 실패시에도 포스맨에 뜰 수 있게 하기
profile
공부하자개발하자으쌰으쌰

1개의 댓글

comment-user-thumbnail
2023년 8월 2일

유익한 글이었습니다.

답글 달기