728x90

The HTTP 401 response code indicates an "Unauthorized" error. This typically means that the request requires user authentication which has not been provided or which has failed. Here are some common reasons and solutions for this issue in a Spring Boot application:

1. Spring Security Configuration

If your Spring Boot application is using Spring Security, it might be configured to require authentication for accessing the API endpoints. This is a common scenario when Spring Security is included in the project dependencies.

Solutions:

  • Provide Authentication Credentials: If your API requires authentication, you need to provide the correct credentials in your request header. In Postman, you can do this in the Authorization tab, selecting the type of authentication your API uses (like Basic Auth, Bearer Token, etc.) and entering the required credentials.
  • Adjust Security Configuration: If the /users endpoint should be publicly accessible without authentication, you'll need to adjust your Spring Security configuration to permit requests to this endpoint. Here’s an example of how you might configure this in your WebSecurityConfigurerAdapter:
@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        // ... other configurations ...
        .authorizeRequests()
        .antMatchers("/users").permitAll() // Permit requests to /users endpoint
        .anyRequest().authenticated()
        // ... other configurations ...
}

 

2. CSRF Protection

Spring Security's CSRF (Cross-Site Request Forgery) protection is enabled by default. If you are making a POST request to your Spring Boot application from Postman or another REST client, CSRF protection might block it.

Solutions:

  • Include CSRF Token: If CSRF protection is necessary (usually for browser-based applications), include the CSRF token in your request.
  • Disable CSRF Protection for API Endpoints: If you're building a stateless REST API (especially one used by non-browser clients), you might consider disabling CSRF protection for those endpoints:
@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        // ... other configurations ...
        .csrf().disable() // Disable CSRF protection
        // ... other configurations ...
}

3. CORS Configuration

While the 401 error isn't directly related to CORS (Cross-Origin Resource Sharing), incorrect CORS settings can sometimes manifest as authentication issues, especially if you're calling the API from a different domain.

Solution:

  • Configure CORS Settings: Ensure that your Spring Boot application has the correct CORS settings if your API is being accessed from a different domain.

4. Check Server Logs

Finally, check your server logs for any additional information or error messages related to the failed request. The logs can provide more specific details about why the request was unauthorized.

By addressing these areas, you should be able to resolve the 401 error and successfully make POST requests to your /users endpoint.

 
 
 
728x90

1. Reserved Keyword 

 GenerationTarget encountered exception accepting command : Error executing DDL "create table evaluation (id bigint generated by default as identity, comment varchar(255), content_id bigint, like boolean, unlike boolean, user_id bigint, primary key (id))" via JDBC [Syntax error in SQL statement "create table evaluation (id bigint generated by default as identity, comment varchar(255), content_id bigint, [*]like boolean, unlike boolean, user_id bigint, primary key (id))"; expected "identifier";]

 

위에서 나온 부분은 Reserved Keyword (예약어) 에 대한 사용이다.

 

 JPA  를 사용할 때에 JPA는 형상변환을 거쳐 SQL 문법 (Diarect)로 변환되게 되는데, 코드상에서 보면 당연히 '좋아요' 를 like로 지정할 수 있겠지만 이러한 부분은 SQL 문법에서의 like 와 문제를 일으키게 된다.

 

문제가 되는 코드를 살펴보자

 

package com.webtoon.webtoonservice.model;

import jakarta.persistence.*;

@Entity
public class Evaluation {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private Long userId;
    private Long contentId;
    private Boolean like;
    private Boolean unlike;
    private String comment; // Ensure validation to disallow special characters
}

 

이 부분에서 해당하는 부분을 고치려면 like를 likes 로 고치거나 이스케이핑을 하면 된다.

 

@Entity
@Table(name = "evaluation")
public class Evaluation {
    // other fields...

    @Column(name = "`like`")
    private Boolean like;
    private Boolean unlike;

    // getters and setters...
}

 


2. Reserved Keyword

GenerationTarget encountered exception accepting command : Error executing DDL "create table user (id bigint generated by default as identity, gender varchar(255), register_date timestamp(6), type varchar(255), user_email varchar(255), user_name varchar(255), primary key (id))" via JDBC [Syntax error in SQL statement "create table [*]user (id bigint generated by default as identity, gender varchar(255), register_date timestamp(6), type varchar(255), user_email varchar(255), user_name varchar(255), primary key (id))"; expected "identifier";]

 

가장 눈치채기 어려운 것 중 하나인 user 에 대한 부분이다. 변환하는 과정 도중 Directs 중에서 user 라는 부분은 이미 잡혀있는 user table 을 지칭하여 문제를 일으킬 수 있기 마련인데 이러한 부분 때문에 문제가 발생한다.

 

package com.webtoon.webtoonservice.model;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;


import jakarta.persistence.*;
import java.util.Date;



@Entity
@Table(name = "`user`") // use backticks to escape
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String userName;
    private String userEmail;
    private String gender; // Consider using an enum here
    private String type;   // Consider using an enum here
    private Date registerDate;
}

 

마찬가지로 이스케이핑을 하여 처리할 수 있다.

'Java > Spring Boot JPA' 카테고리의 다른 글

[Trouble Shooting] Open API  (1) 2024.02.01
HTTP 401 response code  (0) 2024.01.12
[Shop] 세션 끊김 문제 완전 해결  (0) 2023.09.21
[Shop] Session Failure Problem  (0) 2023.09.16
[sync] Complete Session Sync issue  (0) 2023.09.01
728x90

전 포스팅에서 한번 언급한 바가 있지만, 고도몰에 접속하거나 토큰에 의해서 데이터를 가져오게 되는 경우 Session 연결을 성립하게 되는 경우다.

 

Android 단에서 ApiService.kt 단에서 GET method 방식으로 Shop의 User Profile 을 확인하는 부분을 추가시켜 주었고, 원래라면 앱이 켜졌을 때마다 accessToken 을 가지고 고도몰에 대해서 End-Point 단위로 request 를 날려주려 했으나 비효율적이라는 판단이 들은 것 같다.

 

1.

앱을 사용하는 사용자들이 전부다 샵을 이용할 계획이 있는 것은 아니기 때문이다.

이러한 부분에서 앱을 키자마자 무조건적으로 샵에 대해서 request 를 전송하게 되면, 불필요한 트래픽과 동시에 request 가 발생하게 된다.

 

2.

WebView 에 의해서 Shop 이 로드됫을 때 (init) 시점마다 request 를 던져주게 되면, 자연스럽게 WebView 안에 있는 Web 에 대해서도 Session Handling 을 할 수 있게 되기 때문에 이 부분이 구조적으로 볼 때에 정상적이라고 볼 수 있을 것 같았다.

 

여하튼 패치 후, 정상적으로 세션 끊김 문제는 해결되었고

 Signed Key를 이용하여 Deploy 를 하기위해 Android Market 에 검토요청을 올렸다.

 

728x90

세션 풀림 문제 중 가장 중요한 것 하나는 Android Side - Back-end Side - Godomall 로 이어지는 연계순서였다.

중간에 이 과정에서 Spring 에서 "Bearer " 에 대한 String 을 떼어버리고 파싱한 뒤에 Godomall 쪽에 이어지는 순서로 접근하게 되는데, 이 과정에서 다시 한 번 Session Connection 이 이루어질 수 있었다.

 

자 그러면 본론으로 돌아가서 왜 한번의 Session 발급 이후에 Session 이 풀리고나서 로그인하기 힘들었던 이유가 있었는지 생각해보자

 

 

1. 

Moyamo Android Side run - init - Shop request 

이 순서상에서 이루어질 때, 앱을 처음 실행한 사용자라던가 캐시가 없는 사용자라면 해당하는 부분에 대해서 다시금 Session Sync 가 이루어졌어야 하기 때문에 한번의 연결은 정상적으로 작동하게 된다.

 

다만 그 이후에 refresh Token 이라던지 access Token 이 들어왔을 때에 주기적으로 돌아야 하는게 없었기 때문이다.

- 물론 이 부분에 대해서 찾아보면 refresh Token 이나 access Token 에 대한 로직이 있을지라도 활성 사용자수인 25만명에비하여 실사용자는 5~7만명에 그칠 것이기에 데이터베이스에서 직접 긁어다가 작동시키는 부분은 생각보다 비효율적인 트래픽을 야기할 수 있다.

 

2.

그렇다면 어차피 끊긴 김에 User의 Shop Profile 을 확인하는 End-Point 를 호출해서 소환하는 구조로 간다.

- 이 경우 Android 사이드에서 앱이 켜질때마다 request 를 날려주는 번거로움이 있긴 하지만 적어도 Session 에 대한 안정성은 보장할 수 있다. 따라서 Web-View 상에서 불러오는 쿠키의 Session 에 대해서도 변함없이 사용자가 서비스를 지속적으로 이용하게 해줄 수 있다.

 

따라서 이번엔 2번으로 접근하는 것을 유도해보고, 1번은 별도의 분석에 들어가기로 했다.

+ Recent posts