반응형
API ?

"API 만들어 본 적 있어?"

친구의 질문으로 시작된 본격 API 파헤치기.. 

여기서 API는 [ Application Programming Interface ]의 약자로, 서로 다른 애플리케이션 사이에서 데이터를 주고 받을 수 있게 해주는 중간 다리 역할 이라고 생각하면 된다.

 

API에는 RESTful API, SOAP API, JPA... 등등 여러 종류가 있다.

 

지금껏 내가 해왔던 프로젝트는 클라이언트와 서버간의 상호작용에 있어서는 전통적인 자바 애플리케이션 @controller를 사용했다. 즉, HTTP 메서드인 GET, POST, PUT, DELETE (소위 CRUD라고 함)를 활용해서 조작하지 않고, @Getmapping, @Postmapping으로 url을 잡고 사용해왔다.

이런 방식은 사실 상 서버 사이드 렌더링을 통해서 웹 페이지를 생성하고 제공하는데에 사용되기 때문에, 서버랑 클라이언트가 강력하게 결합되어 있어서 서버-클라이언트 간의 독립성은 떨어진다. (한 마디로 정말 간단한 웹 서비스 개발..)

[서버사이드 렌더링이 뭐고] ↴

더보기

서버 사이드 렌더링이 무슨말이냐구요?

 

서버 사이드 렌더링(Server-Side Rendering, SSR)은 웹 애플리케이션의 사용자 인터페이스(UI)를 서버에서 생성하고 초기 로드 시에 클라이언트에게 완전한 HTML 페이지를 제공하는 웹 개발 기술입니다. 이것은 클라이언트 사이드 렌더링(Client-Side Rendering, CSR)과 대조적입니다.

SSR의 작동 방식은 다음과 같습니다:

  1. 클라이언트에서 웹 페이지 요청을 서버로 보냅니다.
  2. 서버는 요청을 받아 해당 요청에 필요한 데이터를 데이터베이스에서 가져오거나 다른 외부 소스로부터 데이터를 가져옵니다.
  3. 서버는 서버 사이드 렌더링 엔진을 사용하여 사용자 인터페이스(UI) 템플릿을 렌더링하고, 데이터를 포함한 HTML 페이지를 생성합니다.
  4. 서버는 완전한 HTML 페이지를 클라이언트에게 반환합니다.
  5. 클라이언트는 받은 HTML을 렌더링하고 페이지를 화면에 표시합니다.

하지만 요즘 대부분의 서비스는 여러 형태의 클라이언트 플랫폼과 서버간의 통신이 이루어지는 방식이기 때문에, 서버와 클라이언트가 독립적이면서도 잘 통신할 수 있도록 하는 방식이 선호된다.

 

그런 방식이 대표적으로 RESTful API라고 할 수 있다.

 

그럼 RESTful API는 뭐야???

 

RESTful API?

RESTfult API는 [ Representational State Transferful Application Programming Interface ]의 약자로, URI에 자원의 정보를 나타내도록 하고, HTTP 메서드( GET, POST, PUT, DELETE  )를 사용해서 자원을 조작하는 것이다.

 

자원?? URI??? 조작???

 

한가지 예를 들어보자.

회원(회원정보)이 있고, 상품(상품정보)이 있다고 가정하자. 각각은 자원이라고 부른다. 

회원 정보에 대해서 조회(GET)를 할수 있고, 새로운 회원 정보를 생성(POST)할 수 있고, 회원 정보를 수정(PUT)할 수 있고, 회원 정보를 삭제(DELETE)할 수 있다.

mapping할 때마다 우리는 URI를 적었다. 그 URI를 자원에 따라서 패턴화 하고, 적절한 HTTP 메서드를 사용함으로써 동작을 정의할 수있다.

  

즉 이와 같이 쓸 수 있다.

  • GET /members: 모든 회원 목록 조회.
  • GET /members/{id}: 특정 회원 조회.
  • POST /members: 새로운 회원 생성.
  • PUT /members/{id}: 특정 회원 수정.
  • DELETE /members/{id}: 특정 회원 삭제.
  • GET /products: 모든 상품 목록 조회.
  • GET /products /{id}: 특정 상품 조회.
  • POST /products : 새로운 상품 생성.
  • PUT /products /{id}: 특정 상품 수정.
  • DELETE /products /{id}: 특정 상품 삭제.

 이렇게 한 자원에 대해서 '/자원'으로 패턴화 하는 과정을 거치고, 그 안의 세부 동작이나 자원에 대해서는 /이하에 붙여서 URI를 통해 자원의 상태를 나타내어 가독성을 높혀주는 것이다.

 

특징을 보면 자원이 모두 복수명사 형태로 표현된 것을 확인 할 수 있다.

리소스 명은 동사보다는 명사를 사용하도록 하는 것이 바람직한 표현 방식이다.

 

따라서 명심하자.

 

GET /members/delete/1  //잘못된 표현

이와 같이 동작을 나타내는 delete를 리소스에 작성하는 것이 아니다.

 

DELETE /members/1  //옳게 수정된 표현

 자원은 명사로만 두고, 동작은 HTTP 메서드로 표현하는 것이다.

 

(URI 설계의 자세한 내용은 아래의 블로그를 참고하자.)

 

 

개발 초보를 위한 RESTful API 설계 가이드

초보자를 위한 RESTful API 설계 가이드를 작성해보았습니다.

velog.io

 

스프링부트에서 코드 상 어떻게 쓰이는지 살펴보자.

@RestController
@RequestMapping("/api/members")
public class MemberRestController {
    // 멤버 API 정의
    
    @GetMapping
    public ResponseEntity<List<MemberDTO>> getAllMembers() {
        // 모든 멤버 목록 조회 로직
        List<MemberDTO> members = memberService.getAllMembers();
        return new ResponseEntity<>(members, HttpStatus.OK);
    }

    @GetMapping("/{id}")
    public ResponseEntity<MemberDTO> getMember(@PathVariable Long id) {
        // 특정 멤버 조회 로직
        MemberDTO member = memberService.getMemberById(id);
        return new ResponseEntity<>(member, HttpStatus.OK);
    }

    @PostMapping
    public ResponseEntity<MemberDTO> createMember(@RequestBody MemberDTO memberDTO) {
        // 새로운 멤버 생성 로직
        MemberDTO createdMember = memberService.createMember(memberDTO);
        return new ResponseEntity<>(createdMember, HttpStatus.CREATED);
    }

    @PutMapping("/{id}")
    public ResponseEntity<MemberDTO> updateMember(@PathVariable Long id, @RequestBody MemberDTO memberDTO) {
        // 특정 멤버 수정 로직
        MemberDTO updatedMember = memberService.updateMember(id, memberDTO);
        return new ResponseEntity<>(updatedMember, HttpStatus.OK);
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteMember(@PathVariable Long id) {
        // 특정 멤버 삭제 로직
        memberService.deleteMember(id);
        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
    }
}

각 객체의 CRUD를 위해서 하나의 RESTController로 정의되는 것을 확인할 수 있다.

어노테이션에 주목하자.

@RestController
@RequestMapping("/api/members")

@RestController를 통해서 RESTful API를 사용하겠다는 것을 나타내고 있다.

@RequestMapping을 통해서 URI 패턴을 정의하기 시작했다. 회원에 대해서는 /api/members가 기본 URI로 동작할 것이다.

그리고 각각의 CRUD 동작에 맞추어서 @Getmapping @Postmapping @Putmapping @Deletemapping을 사용하고 있는 것을 확인할 수 있다.

 

여기서 또 중요한 점!!!

 

기존 프로젝트에서는 CRUD결과 html 페이지(main.html 이런 파일 자체)를 반환했었는데에 반해(그래서 더욱 결합이 된 것일지도..), RESTful API 방식에서는 ResponseEntity를 반환하고 있다!!!??

 

ResponseEntity ?

ResponseEntity는 Spring Framework에서 제공하는 클래스로, HTTP 응답을 나타내는 객체이다. 이 클래스를 사용하여 클라이언트에게 HTTP 응답을 구성하고 전달할 수 있다.

 

왜 이 객체를 반환하는 것일까?

 

그건 바로 RESTful API 방식에서의 HTTP 응답 형식은 JSON이나 XML같은 데이터 형식을 사용함으로써 클라이언트에 응답하기 때문이다. 따라서 반드시 반환 형태를 JSON 또는 XML형태의 데이터로 주어야 한다.

 

ResponseEntity는 다음과 같은 기능을 제공한다. 

  1. HTTP 응답 상태 코드 설정
  2. HTTP 응답 헤더 설정
  3. 응답 본문 데이터 설정
  4. 응답 타입 설정

 

이것도 코드를 통해서 쓰임을 살펴보자.

 

@GetMapping
    public ResponseEntity<List<MemberDTO>> getAllMembers() {
        // 모든 멤버 목록 조회 로직
        List<MemberDTO> members = memberService.getAllMembers();
        return new ResponseEntity<>(members, HttpStatus.OK);
    }

 매핑 결과 ResponseEntity 객체를 new로 생성해서 members의 정보와 함께 HttpStatus.OK라는 것을 담아 반환하고 있다.

members는 조회 결과를 담은 데이터를 반환해 준 것일테고, HttpStatus.OK가 조금 생소하다.

 

HttpStatus.OK가 바로 ResponseEntity의 기능 1번인 HTTP 응답 상태 코드를 나타내는데, 의미는 200 OK 상태를 나타내는 코드이다.=말 그대로 OK= 요청이 성공적으로 처리되었음

HttpStatus.NOT_FOUND라는 코드는 404 not found 상태를 반환하라는 의미이다.= 요청한 리소스를 찾을 수 없음

(상태별로 코드가 정리된 표도 위 참고 블로그에 있으니 참고하자.)

 

상태 정보를 넘기는 이유가 뭘까?

상태코드 ?

상태 코드는 서버가 클라이언트에게 요청을 처리한 결과를 전달하는 수단이다. 클라이언트는 상태 코드를 통해 요청이 성공했는지, 실패했는지, 어떤 종류의 오류가 발생했는지 등을 파악할 수 있다.

 

클라이언트는 상태 코드를 기반으로 다음 단계를 결정할 수 있다. 예를 들어, 성공적인 응답(예: 200 OK)일 경우 데이터를 표시하고, 오류 응답(예: 404 Not Found)일 경우 오류 메시지를 표시하거나 다른 조치를 취할 수 있다.

 

이 외에도 다양한 이유가 있지만, 서버와 클라이언트 간의 정확하고 원활한 상호작용을 위해서가 중점이라고 할 수 있겠다.

 

 

마지막으로 한가지 더 잡고 넘어가야 할 부분이 있다.

 

바로 '세션' 문제인데, 기존의 프로젝트 코드(전통적인 웹 애플리케이션 방식)에서는 @HttpSession을 통해서 로그인 상태를 세션을 통해 유지할 수 있었다.

근데 RESTful API방식은 상태를 관리하지 않는 stateless 방식을 따른다. 각 요청이 독립적이고, 서버는 클라이언트의 상태를 유지하지 않기 때문에, 클라이언트는 요청을 할 때 요청 정보를 함께 제공해 주는 과정이 필요하다!!

 

예를 들어서 인증 정보는 요청 헤더에 토큰 또는 인증 정보를 포함하여 전송할 수 있다. 토큰 기반 인증을 사용해 사용자 인증을 하고 상태 관리를 할 수 있는 것이다.

 

RESTful API에서의 토큰 기반 인증:

  1. 사용자가 서버에 로그인하면 서버는 사용자에게 액세스 토큰(access token)을 발급합니다.
  2. 클라이언트는 액세스 토큰을 안전한 방식으로 저장하고 각 요청에 포함시켜 서버로 보냅니다. 일반적으로 요청의 헤더에 포함됩니다.
  3. 서버는 액세스 토큰을 검증하고, 유효한 토큰인 경우 해당 사용자를 식별하고 요청을 처리합니다.

요청의 헤더가 어디일까..~

 

일반적으로 사용되는 토큰 기반 인증 방식 중에는 OAuth 2.0 및 JWT(Json Web Token)가 있습니다. 이러한 인증 방식을 사용하여 RESTful API에서 사용자 인증 및 세션 관리를 구현할 수 있습니다.

 

OAuth...!!! 이번 정처기 실기에 나왔던 개념인데, 이걸 먼저 공부했더라면 맞힐 수 있었을텐데..

 

토큰 관련해서는 좀 더 공부가 필요할 것으로 보인다. 과거에 express랑 node.js로 개발했을 때 로그인에서 한번 쓴 것 같기도 한데(토큰 유효 시간 설정하고 그랬었음), 기억이 잘 나지 않은 것 보니.. RESTful API로 한번 프로젝트 파서 직접 해봐야겠다!!!

 

할거 +1됨.

 

 

 

반응형
반응형

서버를 클라우드에 올려 다수의 클라이언트들이 서비스를 이용한다고 하자.

 

수많은 클라이언트들의 요청은 쏟아지는데, 서버가 하나라면? 트래픽이 몰리게 되어 서버가 터져버리고 말 것이다. 

 

따라서 서버를 여러개 구축해서, 각 서버가 동일한 데이터를 갖도록 하고, 여러 요청을 해결할 수 있다.

 

그런데 여러대의 서버로 들어오는 트래픽을 제대로 분산하지 못한다면? 하나의 서버로 몰리게 되어 결국 효과는 없을것이다.

 

그러므로, 쏟아지는 트래픽을 여러대의 서버로 균등하게 분산시켜주는 기술이 필요하고, 그게 바로 "로드밸런싱" 이다!

 

 💡 로드밸런서 ???

로드밸런서 아키텍처

로드밸런서는 로드밸런싱을 해주는 장치라고 생각하면 된다!

로드(load) = 서버에 가해지는 부하, 밸런서(balancer) = 분산의 합성어이다.

 

로드밸런서는 사진에서와 같이, 클라이언트와 서버풀(분산 네트워크 서버집합) 사이에 위치하여, 쏟아지는 트래픽을 각 서버에 동등하게 나누어 주는 역할을 한다.

 

로드밸런싱이 필수일까?

 

서버를 사용하는 클라이언트 수가 적다면, 하나의 서버로도 충분히 서비스 운영이 가능하다. 

그렇지만 사업이 커지고 클라이언트 수가 많아진다면 그 만큼 요청 트래픽도 증가 할것이기 때문에 분산 처리를 해주는 것이 좋고, 따라서 로드 밸런싱이 필요하다.

 

늘어나는 트래픽에 대처할 수 있는 방법에는 두가지가 있다.

 

scale-up 과 scale-down

 

scale-up은 하나의 서버의 성능을 높혀주는 것이다.

scale-down은 비슷한 서버의 성능을 여러개로 증축하는 것이다.

 

scale-up 과 scale-down

분산 서버에 로드밸런싱 기술을 적용해야 하므로 scale-out 방식으로 트래픽을 해결할 경우에, 로드밸런서 장치가 사용될 수 있다.

 

 

로드밸런싱에는 다양한 알고리즘이 있다.

 

  • 라운드 로빈 알고리즘  :  클라이언트의 요청이 들어오는 순서대로, 각 서버에 차례로 분배한다. 따라서 서버의 세션 지속 시간이 길지 않은 서비스의 경우 사용하면 좋은 알고리즘이다.
  • 가중 라운드 로빈 알고리즘 : 각 서버가 서로 다른 성능을 가지고 있을 때 사용하는 것으로, 성능에 따른 가중치를 부여하고, 그에 맞게 트래픽을 분산한다. 예를 들어서 서버 A의 가중치가 5, 서버 B의 가중치가 2이라면, A에는 5개의 요청을, B에는 2개의 요청을 전달해서 트래픽을 분산하는 방식이다.
  • IP 해시 방식 : 클라이언트의 ip를 해싱해서 특정 서버로 매핑하여 요청을 처리한다. 따라서 클라이언트는 항상 동일한 서버로 연결됨을 보장할 수 있다.
  • 최소 연결 방식 : 요청이 들어온 시점에 가장 적은 연결상태를 보이는 서버에 우선적으로 트래픽을 배분한다. 
  • 최소 리스폰타임 : 서버의 현재 연결상태와 응답시간을 고려해서 최적인 서버에 우선적으로 트래픽을 배분한다. 즉 가장 적은 연결 상태와 가장 짧은 응답시간을 보이는 서버에 먼저 할당된다.

 

 

 

 

반응형

'CS' 카테고리의 다른 글

ERP & CRM 개념 알기 / 비즈니스 소프트웨어  (0) 2023.12.20
반응형
💡 DRS(Disaster Recovery System)의 유형
  • mirror site : RTO=0
  • Hot site : RTO 4시간 이내
  • Warm site : RTO 수일~수주
  • Cold site : RTO 수주~수개월

 

💡 데이터베이스의 특성
  • 실시간 접근성
  • 계속적인 변화
  • 동시 공용
  • 내용 참조

 

💡 데이터베이스 정규화 단계
  • 1NF : 원자화
  • 2NF : 부분함수 종속 제거
  • 3NF : 이행함수 종속 제거
  • BCNF : 결정자 함수 종속 제거
  • 4NF : 다치 종속 제거
  • 5NF : 조인 종속 제거
두부이걸다줘? = 도부이결다조

 

💡 병행제어
다수 사용자 환경에서 / 여러 트랜잭션을 수행할 때 / 데이터베이스 일관성 유지를 위해 / 상호작용을 제어하는 기법

 

 

💡 EAI 구성요소
  • EAI 플랫폼
  • 어댑터(연결해준다)
  • 브로커
  • 메시지 큐
  • 비즈니스 워크플로우

 

💡 고가용성 유형
  • Hot Standby : 상시 대기, 장애 시 전환
  • Mutual Take-Over : 둘 중 하나 장애 시 -> fail over , 상부상조
  • Concurrent Access : 둘 중 하나 장애 발생하더라도 fail over 하지 X

 

💡 MAC vs MDC
  • MAC : Message Authentication Code, 키O, 인증
  • MDC : Modification Detection Code, 키X, 감지

 

💡 병행제어 기법
  • 로킹
  • 낙관적 검증
  • 타임스탬프 순서
  • MVCC
로 낙타다!

 

💡 소프트웨어 생명주기 프로세스
요구사항 분석 → 설계 → 구현 → 테스트 → 유지보수  
요설구테유

 

 

💡 논리적 데이터 모델링
  • 관계 데이터 모델 : 2차원 테이블 형태
  • 계층 데이터 모델 : 트리 형태
  • 네트워크 데이터 모델 : 그래프 형태

 

💡 SQL 제약조건 
  • CHECK
    CHECK(참이 되는 조건)
    ⇒ CHECK(성별 IN('M', 'F'))
    또는
    CHECK(성별 = 'M' OR 성별 = 'F')
  • DEFAULT
    기본값
    DEFAULT 3 ⇨ 3으로 초기화한다.

 

💡 SW 개발 보안의 3대요소
  • 기밀성
  • 무결성
  • 가용성
기무가

 

💡 IT 업무 프로세스 관련 용어
  • ITSM : IT Service Management
  • SLA : Service Level Agreement , 고객과 서비스 제공자 간 계약

 

💡 시스템 보안 공격 (정보보호론에서 배운 것 생각!!!)
  • 스택 버퍼 오버플로우 공격
    solution :
    스택 가드 활용(카나리라고 하는 체크용 값을 확인),
    스택 쉴드 활용(리턴 주소를 비교)

 

💡 소프트웨어 아키텍처 패턴 유형
  • 계층화 패턴 = 레이어 패턴 : 서로 마주보는 두개의 계층
  • 클라이언트-서버 패턴
  • 파이프-필터 패턴 : 스트림, 다음으로 넘겨주는 과정 반복
  • MVC 패턴 : 별도의 컴포넌트, 대화형 애플리케이션
  • 브로크 패턴 : 통신 조정

 

💡 분석 자동화 도구 (CASE)
  • 상위 CASE : 자료 흐름도
  • 하위 CASE : 구문 중심

 

💡 REVOKE 명령에 CASCADE CONSTRAINTS 
REVOKE 명령문 끝에 CASCADE CONSTRAINTS 를 붙이면 
연쇄적 권한 해제를 의미 = WITH GRANT OPTION 으로 부여된 사용자 권한까지 해제

 

💡 유스케이스 다이어그램 구성요소와 구성요소 간 관계
  • 유스케이스 : 서비스
  • 액터 : 역할
  • 시스템
  • 구성요소간 관계 : 확장관계 / 포함관계 / 일반화관계

 

💡 데이터베이스 고립화 수준 (ISOLATION LEVEL)
  • READ UNCOMMITTED
  • READ COMMITTED
  • REPEATABLE READ
  • SERIALIZABLE READ

 

💡 애플리케이션 공격 기법 유형
  • HTTP GET 플러딩 : 서버 자원 소진
  • Slow HTTP Header DoS : 개행 문자열
  • Slow HTTP POST DoS : 헤더의 content-length를 비정상적으로 크게
  • Slow Read Attack : TCP윈도 크기 ↓, 데이터 처리율↓
  • Hulk DoS : 웹 페이지 주소를 지속적으로 변경
  • Hash DoS : 해시충돌

 

💡 데이터 웨어하우스 vs 데이터 마트
  • 데이터 웨어하우스 : 통합 관리 DB
  • 데이터 마트 : 특정 조직

 

💡 프로세스 관련 용어
  • TPS : TRANSACTION PER SECOND
  • 반환시간(Turnaround Time) : 프로세스의 입력~결과 산출 까지 소요 시간

 

💡 UI 화면 설계
  • 와이어프레임 : 화면 단위의 레이아웃 설계
  • 스토리보드
  • 프로토타입 : 정적 화면 → 동적 시뮬레이션 모형
와 스프!!

 

💡 객체지향 설계 원칙 (SOLID)
  • 단일 책임의 원칙
  • 개방-폐쇄의 원칙
  • 리스코프 치환의 원칙
  • 인터페이스 분리의 원칙
  • 의존성 역전의 원칙

 

💡 SWITCH-CASE 문 주의 할 점
int num = 10;
switch(num){
   case 10:
   case 9 : return 'A'; break;
   case 8 : return 'B'; break;
   default : return 'C'; 
}

위와 같은 상황에서 case 10이 실행되지만, 아무것도 하지 않고 break문도 없다. 이럴 경우 case 9로 넘어가서 A를 반환하고, break문을 만났으므로 swich문을 빠져나온다.
case 10에서 break이 없다고 해서 default로 가는 것이 아님을 명심하자!!!
반응형
반응형
💡 WHY?
  • 기존의 스프링부트 프로젝트는 로그인을 하지 않더라도 페이지의 주소만 알면 접근이 가능했던(물론 로그인 정보는 뜨지 않지만) 문제가 있었다.
  • 페이지 접근에 있어서 로그인 한 경우에만 로그인 페이지 그 외의 페이지들을 접근할 수 있도록 하는 기능이 필요하다.
  • 이를 해결하기 위해 '스프링부트 Security'를 적용해보자.

 

아직 spring security에 대한 기본 지식이 많이 부족하므로, 기본적인 것부터 하나씩 추가해보려고 한다.

 

 

Spring Security 기본 설정 시작
  • Gradle에 security 의존성을 추가해준다.
    (gradle 수정 후에는 항상 build(코끼리 누르기)해 줄 것을 잊지말 것!)
implementation 'org.springframework.boot:spring-boot-starter-security'//spring security 추가
  • security 클래스 추가하기.
    config 디렉토리 하에 security 디렉토리를 생성해준 후, LoginIdPwValidator.javaSpringSecurityConfig.java 클래스를 생성해준다.

config 클래스 추가

 

  • 일단 LoginIdPwValidator는 건너 뛴다.

  • SpringSecurityConfig 클래스를 아래와 같이 설정해준다.
@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .defaultSuccessUrl("/main", true)//"/"로 가도 됨.
                .permitAll()
                .and()
                .logout();
    }
}
  • SpringSecurityConfig 클래스는 WebSecurityConfigurerAdapter를 상속받아 사용하고, WebSecurityConfigurerAdapter에 정의된 다양한 security함수들을 오버라이딩하여 목적에 맞게 사용할 수 있다.
  • 이 때 @Configuration과 @EnableWebSecurity 어노테이션을 추가해 주면 된다.
  • configure함수를 오버라이딩 한 것이고, 일단은 HttpSecurity 만을 인자로 가지도록 하였다.

 

  • 아래 함수의 역할은 '어떤 URI로 접근하든지 인증이 필요하다'는 것이다.
anyRequest().authenticated()
  • 아래 함수의 역할은 '폼 방식 로그인을 사용할 것'임을 나타내고, 아래 로그아웃도 추가해주었다.
formLogin()
  • 아래 함수의 역할은 '로그인이 완료되면 해당 URI로 이동할 것'임을 나타낸다.
defaultSuccessUrl("/main", true)

 

스프링 시큐리티 예외 처리

현재 상태는 모든 경로에 대해서 사용자 접근이 제한되어 있다. 

로그인 페이지나 소개 페이지 같은 페이지들은 로그인 없이도 접근 가능해야 한다.

따라서 특정 페이지에 대한 경로 제한을 풀어주는 예외처리가 필요하다.

로그인페이지의 URI는 "/"이므로 이 경로에 대해서만 접근을 허용하기 위해 다음과 같은 코드를 SpringSecurityConfig에 추가해 주어야 한다.

'.antMatchers("/").permitAll()'

여기서 .antMatchers("/")는 Spring Security에서 URL 경로에 대한 권한 설정을 하는 부분 중 하나이다. 이 설정은 "/" 경로에 대한 URL 접근을 나타낸다.

여기에 .permitAll()을 붙여주면 모든 사용자가 이 경로에 접근하도록 허용한다.

따라서 이 코드는 로그인페이지에 대해서는 예외적으로 모든 사용자가 로그인을 하지않아도 접근할 수 있게 해준다.

 

허용하고 싶은 페이지가 여러 개라면, .antMatchers("/","/a",..) 이런식으로 경로를 나열해주면 된다.

 

백엔드와 프론트엔드가 분리되지 않은 프로젝트(스프링부트에서 jsp나 타임리프를 붙여서 하나의 프로젝트로 백엔드+프론트엔드를 전부 처리하는 프로젝트)는 css나 이미지 파일 등의 경우 인증이 되지 않은 상태에서도 보여져야 할 수 있다. 이 경우에는 별도로 WebSecurity 하나를 인자로 갖는 configure를 오버라이딩 해서 예외 처리를 할 수 있다.

 

위에서 설명한 두가지 예외처리에 대해 적용하면 아래와 같다.

 

@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/").permitAll()//로그인 페이지를 제외하고 나머지 페이지는 접근 금지
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .defaultSuccessUrl("/main", true)//"/"로 가도 됨.
                .permitAll()
                .and()
                .logout();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/static/**");
    }
}

 

내 프로젝트의 경우 /static 폴더 하에 바로 img들이 있고, css 파일이 있으므로 static폴더 하위에 대해 보안 설정에 있어 모두 예외처리를 해주도록 하였다.

 

 

 

 

 

 

오늘은 여기까지.

 

📒 아래의 블로그를 참고함.
https://nahwasa.com/entry/%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-Spring-Security-%EA%B8%B0%EB%B3%B8-%EC%84%B8%ED%8C%85-%EC%8A%A4%ED%94%84%EB%A7%81-%EC%8B%9C%ED%81%90%EB%A6%AC%ED%8B%B0
 

스프링부트 Spring Security 기본 세팅 (스프링 시큐리티)

[ 2023-02-10 추가 ] 스프링부트 3.0 이상에 적용하실 경우 '스프링부트 3.0이상 Spring Security 기본 세팅 (스프링 시큐리티)' 글을 참고해주세요. 버전 상관없이 시큐리티 기본 세팅을 익히실 경우에도

nahwasa.com

 

반응형
반응형
대충 만든 자판

이제는 익숙해진 문자열과 숫자 한번에 다루기!

 

문제를 몇번 풀어보니, 이 문제 역시 문자열과 숫자 개념이 더해진 것임을 바로 파악할 수 있었고, map을 사용하여 쉽게 해결할 수 있었다.

 

자판의 등장하는 문자를 char형태의 index로 보고, 어떤 위치의 버튼이든 최소한으로 눌렀을 때를 그 알파벳의 버튼 횟수로 저장하도록 하였다.

 

그러니까 keymap을 순회하면서, 등장하는 문자를 map의 인덱스로 넣고, 해당 위치를 저장하였다.

그리고 같은 문자가 또 한번 등장할 때마다 기존에 저장해 두었던 위치와 비교해보아서 더 작은 위치로 갱신되도록 하였다.

 

이렇게 하여 문자당 최소 터치 수를 map에 저장해 두면 80 프로는 다 한 것이다!!

 

이제 targets을 순회하면서 해당 문자의 최소 터치 수가 저장된 map에서 값을 가져와 count시키고, 

만약 해당 문자가 map에 존재하지 않는다면, 작성할 수 없는 문자열이므로, 문제에서 요구한 것처럼 count를 -1로 하고, 해당 문자열은 넘어가도록 코드를 구현했다.

 

그리고 한 문자열씩 돌때마다 answer벡터에 count값을 push해주면 끝!

 

코드는 아래와 같다.

#include <string>
#include <vector>
#include <map>

using namespace std;

vector<int> solution(vector<string> keymap, vector<string> targets) {
    vector<int> answer;
    
    map<char, int> m1;

	for (int i = 0; i < keymap.size(); i++) {
		for (int j = 0; j < keymap[i].size(); j++) {
			if (m1.find(keymap[i][j]) == m1.end()) {//map에 존재하지 않은 문자면 입력
				m1.insert(pair<char, int>(keymap[i][j], j+1));
			}
			else {
				if (m1[keymap[i][j]] > j + 1) {
					m1[keymap[i][j]] = j + 1;//더작은 값으로 바꾼다
				}
			}
		}
	}

	int cnt;

	for (int i = 0; i < targets.size(); i++) {
		cnt = 0;
		for (int j = 0; j < targets[i].size(); j++) {
			if (m1.find(targets[i][j]) == m1.end()) {
				cnt = -1;
				break;
			}
			auto temp = targets[i][j];
			cnt += m1[temp];
		}
		answer.push_back(cnt);
	}

    
    return answer;
}
반응형
반응형
n칸의 벽 중 덧칠해야 할 칸 번호가 적힌 벡터를 참고하여, 한번에 m칸 칠할 수 있는 페인트 롤러를 이용해 최소의 페인트칠 횟수 구하는 문제.

 

문제의 조건을 보면 section 벡터의 크기가 무조건 1이상이므로, 최소 한번은 칠해야 한다는 점을 기억하자.

 

section[0]에서 시작해서 한번 칠할 때 section[0]+m-1번 칸 까지는 칠해진다.

 

그리고 한번 칠했으므로, 칠한 횟수(answer)를 1 증가시켜준다.

 

temp에 section[0]+m에 대한 값을 저장해두고, for문을 통해 section[1]부터 section의 크기만큼 순회한다.

 

그래서, 다음 칠해야 할 칸이, 이전에 한번 칠했던 범위에 포함이 되는지를 살펴보고, 포함이 된다면 현재 회차는 넘어가도록 한다.이는 현재 section[i]의 값이 temp보다 작은지를 보면 된다.

 

만약 현재 section[i]의 값이 temp와 같거나 더 크다면 이전에 칠했을 때, 같이 칠해지지 못한 것이므로, temp를 다시 section[i]+m으로 갱신해주고, 이를 기준으로 한번 더 칠하는 것이므로 answer를 1 증가 시킨다.

 

위 과정을 모든 section벡터 값에 대해 순회해주면 최소 페인트 칠 횟수를 반환할 수 있다! 

코드는 아래와 같다.

 

#include <string>
#include <vector>

using namespace std;

int solution(int n, int m, vector<int> section) {
    int answer = 0;
    
    int temp = section[0] + m;
	answer++;
	
	for (int i = 1; i < section.size(); i++) {
		if (section[i] < temp) {//한번 칠한것에 같이 포함이 되면
			continue;//넘어간다
		}
		else {
			temp = section[i] + m;
			answer++;
		}
	}
    
    return answer;
}
반응형

+ Recent posts