Backend๐Ÿ–ฅ๏ธ/Javaโ˜•(Spring๐Ÿƒ)

[Spring] JWT ์ด์šฉํ•ด์„œ ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ ๋งŒ๋“ค๊ธฐ - ์‚ฌ์šฉ์ž ๊ฒ€์ฆ

JanuDev 2025. 12. 31. 10:07

๋„ˆ๋ฌด ๊ธธ์–ด์ ธ์„œ ์„ค๋ช… ๋”ฐ๋กœ ๋ถ„๋ฆฌํ•œ๋‹ค.

@Service
@RequiredArgsConstructor
@Slf4j
public class AuthService {

    private final AuthenticateHandler authenticateHandler;
    private final JwtProvider jwtProvider;
    private final UserDetailsServiceImpl userDetailsServiceImpl;

    public TokenDTO login(LoginRequestDTO request) {
        PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

        /*
        * (1) ์‚ฌ์šฉ์ž ๊ฒ€์ฆ(UserDetailsService)
        * */
        UserDetailsDTO userDetails = (UserDetailsDTO) userDetailsServiceImpl.loadUserByUsername(request.getUserId());

        /*
        * (2) ๋น„๋ฐ€๋ฒˆํ˜ธ ๋น„๊ต(PasswordEncoder)
        * */
        if (!passwordEncoder.matches(request.getPassword(), userDetails.getPassword())) {
            throw new BadCredentialsException("๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์•„!(T_T)");
        }

        /*
        * (3) Authentication ๊ฐ์ฒด ์ƒ์„ฑ
        * */
        Authentication authentication = authenticateHandler.authenticate(request);

        // (4) JWT ๋ฐœ๊ธ‰
        String accessToken = jwtProvider.createAccessToken(authentication);

        // (5) ํด๋ผ์ด์–ธํŠธ์— ํ† ํฐ ์ „๋‹ฌ
        return new TokenDTO(accessToken);
    }

}

์—ฌ๊ธฐ์„œ ์ฒซ๋ฒˆ์งธ ์ˆœ์„œ ์„ค๋ช…!

UserDetailsDTO userDetails = (UserDetailsDTO) userDetailsServiceImpl.loadUserByUsername(request.getUserId());

(1) UserDetailsDTO

DB์—์„œ ๊บผ๋‚ธ ๋ฐ์ดํ„ฐ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๋‚ ๊ฒƒ ๊ทธ๋Œ€๋กœ์˜ ์ •๋ณด์ด๋‹ค.

๊ทธ๋ž˜์„œ USER ํ…Œ์ด๋ธ” = ํ˜„์‹ค ์„ธ๊ณ„์˜ ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ์ด๋‹ค.

 

๋ฐ˜๋ฉด์— 

UserDetails = ์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ๊ฐ€ ์ดํ•ดํ•˜๋Š” '์ธ์ฆ์šฉ ์ธ๊ฐ„'์ด๋‹ค.

 

  • DB → UserDTO (๊ทธ๋ƒฅ ๋ฐ์ดํ„ฐ)
  • UserDTO → UserDetailsDTO (์ธ์ฆ์šฉ ๊ฐ์ฒด)

๊ทธ๋ฆฌ๊ณ  UserDetailsDTO๋Š” UserDetails ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ฐ€์ ธ์™€์„œ ๊ตฌํ˜„ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์–ด์ฐจํ”ผ UserDTO์™€ ํ•ฉ์ณ์„œ ์‚ฌ์šฉํ•˜์ง„ ๋ชปํ•œ๋‹ค.

@Getter
@Setter
@ToString
public class UserDetailsDTO implements UserDetails {

    private String userCd;
    private String userId;
    private String userNm;
    private String password;

    // ์žˆ์œผ๋‚˜ ์—†์œผ๋‚˜
    private String bgColor;
    private String textColor;
    private String insertDatetime;

    /*
    * 1. Lombok ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•ด๋„ UserDetails์—์„œ ์š”๊ตฌํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋Š” ์ง์ ‘ ์ž‘์„ฑํ•ด์•ผ ํ•œ๋‹ค.
    * */

    private final String role = "ROLE_USER";

    @Override
    public String getUsername() {
        return userId;
    }

    @Override
    public String getPassword() {
        return password;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        // ๊ณ ์ • ๋ฐ˜ํ™˜
        return List.of(new SimpleGrantedAuthority(this.role));
    }

    /**
     * ํ˜•์‹์ ์ธ ์š”์†Œ๋“ค : true๋กœ ๊ณ ์ •
     * */
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }

}

 

1๏ธโƒฃ public class UserDetailsDTO implements UserDetails

UserDetails๋Š” Spring Security๊ฐ€ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•ด ๊ฐ•์ œ๋กœ ์š”๊ตฌํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค์ด๋‹ค.

์ด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ–ˆ๋‹ค๋Š”๊ฑด ๐Ÿ‘‰ “์ด ๊ฐ์ฒด๋Š” ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž๋กœ ์จ๋„ ๋œ๋‹ค”๋Š” ๋œป.

๊ธฐ์กด์˜ UserDTO์™€ ๋ถ„๋ฆฌํ•œ ์ด์œ .

 

2๏ธโƒฃ ํ•„๋“œ๋ถ€ ์ž‘์„ฑ

๋ณด์•ˆ์— ์ง์ ‘ ๊ด€์—ฌํ•˜๋Š”๊ฑด ์•„๋‹ˆ์ง€๋งŒ ๊ฐ ํ”„๋กœ์ ํŠธ๋ณ„๋กœ ํ•„์š”ํ•œ User์˜ ์ •๋ณด๋ฅผ ์ž‘์„ฑํ•œ๋‹ค.

 

3๏ธโƒฃ ๊ถŒํ•œ(role) ์„ค๊ณ„ - private final String role = "ROLE_USER"

Spring Security๋Š” ๊ถŒํ•œ ์ด๋ฆ„์ด ๋ฐ˜๋“œ์‹œ ROLE_๋กœ ์‹œ์ž‘ํ•ด์•ผ ํ•œ๋‹ค.

 

  • USER โŒ
  • ROLE_USER โญ•๏ธ

์ง€๊ธˆ ๋‚ด ํ”„๋กœ์ ํŠธ์˜ ๊ฒฝ์šฐ ๊ถŒํ•œ์€ ๋”ฑํžˆ ์—†์–ด์„œ... ๊ทธ๋ƒฅ ROLE_USER๋กœ ๋ฐ•์•„๋’€๋‹ค. ๋‚˜์ค‘์— ํ•„์š”ํ•˜๋ฉด ๋ฐ”๋€”์ˆ˜๋„...? ์•„์ง์€ ๊ณ„ํšx

 

4๏ธโƒฃ ํ•ต์‹ฌ ๋ฉ”์†Œ๋“œ

  • getUsername() : Spring Security๊ฐ€ "์ด ์‚ฌ์šฉ์ž์˜ ์•„์ด๋””๊ฐ€ ๋ฌด์—‡์ธ๊ฐ€" ๋ผ๊ณ  ๋ฌผ์„ ๋•Œ ํ˜ธ์ถœ๋œ๋‹ค. ๋ณดํ†ต userId๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š”๊ฒŒ ์ •์„(์ •๋‹ต์€ ์•„๋‹˜~)
  • getPassword() : DB์—์„œ ์ €์žฅ๋œ ์•”ํ˜ธํ™”๋œ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค. ์ธ์ฆ ๊ณผ์ •์—์„œ PasswordEncoder.matches()์— ์‚ฌ์šฉ๋จ
  • getAuthorities() : "์ด ์‚ฌ์šฉ์ž์˜ ๊ถŒํ•œ์„ ์ •์˜" 
    • GrantedAuthority : ๊ถŒํ•œ ์ธํ„ฐํŽ˜์ด์Šค
    • SimpleGrantedAuthority : ๊ฐ€์žฅ ๊ธฐ๋ณธ์˜ ๊ตฌํ˜„์ฒด

5๏ธโƒฃ ๊ณ„์ • ์ƒํƒœ ๊ด€๋ จ ๋ฉ”์†Œ๋“œ

๋ณดํ†ต ํ˜•์‹์ ์ธ ์š”์†Œ๋“ค์ด๊ธฐ ๋•Œ๋ฌธ์— true๋กœ ๊ณ ์ •ํ•œ๋‹ค.

  • public boolean isAccountNonExpired() { return true; } : ๊ณ„์ • ๋งŒ๋ฃŒ ์—ฌ๋ถ€
  • public boolean isAccountNonLocked() { return true; } : ๊ณ„์ • ์ž ๊น€ ์—ฌ๋ถ€. ๋กœ๊ทธ์ธ ์‹คํŒจ 5ํšŒ ์ •์ฑ…๋งŒ๋“ค ๋•Œ ์‚ฌ์šฉ
  • public boolean isCredentialsNonExpired() { return true; } : ๋น„๋ฐ€๋ฒˆํ˜ธ ๋งŒ๋ฃŒ ์—ฌ๋ถ€. 90์ผ๋งˆ๋‹ค ๋ณ€๊ฒฝ ์ •์ฑ… ๋•Œ ์‚ฌ์šฉ
  • public boolean isEnabled() { return true; } : ๊ณ„์ • ํ™œ์„ฑํ™” ์—ฌ๋ถ€. ํƒˆํ‡ด, ํœด๋ฉด ๊ณ„์ • ์ฒ˜๋ฆฌํ•  ๋•Œ ์‚ฌ์šฉ

์ €๋Ÿฐ๊ฑฐ ๋งŒ๋“ค๋ฉด ์ข‹๊ธด ํ•œ๋ฐ.. ๋‚ด ํ”„๋กœ์ ํŠธ๋Š” ์ œ์•ฝ์ด ์—†๋Š” ํ›„๋ฆฌ(?)ํ•œ ์Šคํƒ€์ผ์„ ์ถ”๊ตฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋”ฐ๋กœ ๊ตฌํ˜„ํ•˜์ง„ ์•Š์•˜๋‹ค.

๋ˆ„๊ฐ€ ์žฅ๋‚œ์งˆํ•˜๋ฉด ๋‚˜์ค‘์—๋ผ๋„ ๊ฐœ๋ฐœ์„ ํ• ๋ ค๋‚˜..?

(2) UserDetailsServiceImpl

์ง€ํ”ผํ‹ฐ์˜ ๊ณ ๊ฒฌ์œผ๋กœ๋Š” ์ด ๋ถ€๋ถ„์ด Spring Security ์ธ์ฆ์˜ "์‹ฌ์žฅ"๋ถ€๋ถ„์ด๋ผ ํ•˜์‹ ๋‹ค.

์ด๋ ‡๊ฒŒ๊นŒ์ง€ ๊ฑฐ์ฐฝํ•œ ํ‘œํ˜„์„ ์“ธ์ค„์ด์•ผ...

@Service
@RequiredArgsConstructor
@Slf4j
public class UserDetailsServiceImpl implements UserDetailsService {

    public final JdbcTemplate jdbcTemplate;

    @Override
    public UserDetails loadUserByUsername(String userId) {
        String sql = "SELECT * FROM \"USER\" WHERE \"USER_ID\" = ?"; // ์—ฌ๊ธฐ ์—๋Ÿฌ๋Š” ๋ฌด์‹œ ๊ฐ€๋Šฅ
        UserDetailsDTO userImpl = new UserDetailsDTO();

        try {
            UserDTO user = jdbcTemplate.queryForObject(
                    sql,
                    new Object[]{userId},
                    (rs, rowNum) -> {   // Mapper
                        UserDTO u = new UserDTO();
                        u.setUserCd(rs.getString("USER_CD"));
                        u.setUserId(rs.getString("USER_ID"));
                        u.setUserNm(rs.getString("USER_NM"));
                        u.setPassword(rs.getString("PASSWORD"));
                        u.setBgColor(rs.getString("BG_COLOR"));
                        u.setTextColor(rs.getString("TEXT_COLOR"));
                        u.setInsertDatetime(rs.getString("INSERT_DATETIME"));
                        return u;
                    }
            );

            if (user == null) {
                throw new UsernameNotFoundException("์‚ฌ์šฉ์ž ์ •๋ณด ์—†์Œ: " + userId);
            }

            userImpl.setUserCd(user.getUserCd());
            userImpl.setUserId(user.getUserId());
            userImpl.setUserNm(user.getUserNm());
            userImpl.setPassword(user.getPassword());
            userImpl.setBgColor(user.getBgColor());
            userImpl.setTextColor(user.getTextColor());
            userImpl.setInsertDatetime(user.getInsertDatetime());
            return userImpl;

        } catch (Exception e) {
            e.printStackTrace();
            throw new UsernameNotFoundException("์‚ฌ์šฉ์ž ์ •๋ณด ์—†์Œ: " + userId);
        }
    }

1๏ธโƒฃ public class UserDetailsServiceImpl implements UserDetailsService

UserDetailsService ๋˜ํ•œ Spring Security๊ฐ€ ๋กœ๊ทธ์ธ ์‹œ ๋ฌด์กฐ๊ฑด ํ˜ธ์ถœํ•˜๋Š” ์„œ๋น„์Šค์ด๋‹ค.

  • ์‚ฌ์šฉ์ž๊ฐ€ ์•„์ด๋”” + ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅ
  • Spring Security๊ฐ€ UserDetailsService๋ฅผ ์ฐพ์Œ
  • loadUserByUsername(username)์„ ์ž๋™์œผ๋กœ ํ˜ธ์ถœ

๋”ฐ๋ผ์„œ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋”ฐ๋กœ ํ˜ธ์ถœํ•˜์ง€ ์•Š์•„๋„ ์ž๋™์œผ๋กœ ์—ฐ๊ฒฐ๋œ๋‹ค.

์ด๊ฑธ ์ง€๊ธˆ implementํ•œ ์ด์œ ๋Š” ๊ทธ ์•ˆ์˜ loadUserByUsername์„ ์˜ค๋ฒ„๋ผ์ด๋“œํ•ด์„œ ์‚ฌ์šฉํ• ๋ ค๊ณ . 

 

2๏ธโƒฃ JDBCTemplate ์„ ํƒ ์ด์œ 

JDBCTemplate๋Š” ๋™๊ธฐ ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•˜๊ณ , ์˜ˆ์™ธ ํ๋ฆ„์ด ๋ช…ํ™•ํ•˜๋ฉฐ, ํŠธ๋žœ์žญ์…˜๊ณผ ๋””๋ฒ„๊น…์ด ์‰ฝ๋‹ค. ์ด๊ฑฐ ์‚ฌ์šฉ ์•ˆํ•˜๋ฉด Supabase SDK๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ˆ˜๋ฐ–์— ์—†๋Š”๋ฐ, ๊ทธ๊ฑฐ ์„ค์น˜ํ•˜๊ณ  ์„ธํŒ…ํ•˜๊ธฐ๊นŒ์ง€ ๋˜ ์—„์ฒญ ์˜ค๋ž˜ ๊ฑธ๋ฆด๊ฒƒ์ด ๋‹น์—ฐ์ง€์‚ฌ, Kotlin ๋น„๋™๊ธฐ์‹ + SDK ์—…๋ฐ์ดํŠธ๋„ ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์ €๊ฒƒ ๊ท€์ฐฎ์Œ ์ด์Šˆ๋กœ JDBCTemplate๋ฅผ ์„ ํƒํ–ˆ๋‹ค...

 

3๏ธโƒฃ public UserDetails loadUserByUsername

์ ˆ๋Œ€๋กœ ์ž„์˜์˜ ๋ฉ”์†Œ๋“œ๊ฐ€ ์•„๋‹ˆ๊ณ , UserDetailsService์— ๋‚ด์žฅ๋˜์–ด ์žˆ๋Š” ๋ฉ”์†Œ๋“œ์ด๋‹ค.

Spring Security ๋‚ด๋ถ€์—์„œ AuthenticationManager → UserDetailsService.loadUserByUsername()์„ ์‹คํ–‰ํ•œ๋‹ค.

๐Ÿ‘‰ ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ๋ฌด์กฐ๊ฑด ์‹คํ–‰๋จ!

 

4๏ธโƒฃ SQL์ž‘์„ฑ๋ฌธ

String sql = "SELECT * FROM \"USER\" WHERE \"USER_ID\" = ? ";

์ฐธ๊ณ ๋กœ ํฐ๋”ฐ์˜ดํ‘œ "USER"๋กœ ์ž‘์„ฑํ•ด์•ผ ํ•˜๋ฏ€๋กœ(PostgreSQL์„ ์‚ฌ์šฉํ•จ, ํ…Œ์ด๋ธ”๋ช… & ์ปฌ๋Ÿผ๋ช…์„ ๋Œ€๋ฌธ์ž๋กœ ํ•จ) ์ด์Šค์ผ€์ดํ”„ ๋ฌธ์ž \๋ฅผ "์•ž์— ๋ฐ˜๋“œ์‹œ ์‚ฌ์šฉํ•ด์ค€๋‹ค. 

์ด๋Ÿฐ์‹์œผ๋กœ ๋นจ๊ฐ„์ƒ‰ ํ‘œ์‹œ์™€ ํ•จ๊ป˜ ์—๋Ÿฌ ๋ฌธ๊ตฌ๊ฐ€ ๋œจ๊ธด ํ•˜๋Š”๋ฐ, sql์€ ์ž˜๋„ ๋Œ์•„๊ฐ„๋‹ค. ์ด๊ฒŒ ์‹ซ์œผ๋ฉด DB์„ค๊ณ„ ๋•Œ ์†Œ๋ฌธ์ž๋กœ ํ•˜๋˜๊ฐ€ใ…Ž

jdbcTemplate.queryForObject(sql, param[], RowMapper)

queryForObject: ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•˜์—ฌ, ๋‹จ ํ•˜๋‚˜์˜ ๊ฐ์ฒด๋ฅผ ์กฐํšŒํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๋ฉ”์†Œ๋“œ. ๋‹จ๊ฑด ์กฐํšŒ์— ์ตœ์ ํ•ฉ. ๊ฒฐ๊ณผ๊ฐ€ 0ํ–‰์ด๊ฑฐ๋‚˜ 2ํ–‰ ์ด์ƒ์ผ ๊ฒฝ์šฐ ์˜ˆ์™ธ ๋ฐ˜ํ™˜, ์ •์ƒ์ธ ๊ฒฝ์šฐ UserDTO ๊ฐ์ฒด ํ•˜๋‚˜ ๋ฐ˜ํ™˜

  • ์ฒซ๋ฒˆ์งธ ์ธ์ž : ์‹คํ–‰ํ•  SQL. ?๋Š” ์•„์ง ๊ฐ’์ด ์—†๋Š” ์ž๋ฆฌ
  • ๋‘๋ฒˆ์งธ ์ธ์ž : ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐฐ์—ด. SQL์˜ ์ฒซ๋ฒˆ์งธ ?์— ์ด ๋ฐฐ์—ด์˜ ์ฒซ๋ฒˆ์งธ ๊ฐ’์ธ userId๋ฅผ ๋„ฃ์–ด๋‹ฌ๋ผ๋Š” ๋œป
  • ์„ธ๋ฒˆ์งธ ์ธ์ž : ๋žŒ๋‹ค์‹ RowMapper

(rs, rowNum) -> {...} : RowMapper์˜ ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„. ์›๋ž˜ ํ˜•ํƒœ๋Š”

public UserDTO mapRow(ResultSet rs, int rowNum)

rs(ResultSet) : DB์—์„œ ์กฐํšŒํ•œ ํ˜„์žฌ ํ–‰. ์ปค์„œ๊ฐ€ ์ด๋ฏธ ํ•ด๋‹น ํ–‰์— ์œ„์น˜ํ•ด ์žˆ์Œ

rowNum : ๋ช‡๋ฒˆ์งธ ํ–‰์ธ์ง€(0๋ถ€ํ„ฐ ์‹œ์ž‘), query()์—์„œ ์—ฌ๋Ÿฌ ํ–‰ ์ฒ˜๋ฆฌํ•  ๋•Œ ์œ ์šฉ

๋žŒ๋‹ค์‹ ๋‚ด๋ถ€์—์„  UserDTO๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ž‘์—…์„ ํ• ๊ฒƒ์ด๋‹ค.

(rs, rowNum) -> {   
    UserDTO u = new UserDTO();
    u.setUserCd(rs.getString("USER_CD"));
    u.setUserId(rs.getString("USER_ID"));
    u.setUserNm(rs.getString("USER_NM"));
    u.setPassword(rs.getString("PASSWORD"));
    u.setBgColor(rs.getString("BG_COLOR"));
    u.setTextColor(rs.getString("TEXT_COLOR"));
    u.setInsertDatetime(rs.getString("INSERT_DATETIME"));
    return u;
}

๊ทธ๋‹ˆ๊นŒ ์‚ฌ์‹ค ์ด๊ฑด,

new RowMapper<UserDTO>() {
    @Override
    public UserDTO mapRow(ResultSet rs, int rowNum) throws SQLException {
        UserDTO u = new UserDTO();
        u.setUserCd(rs.getString("USER_CD"));
        u.setUserId(rs.getString("USER_ID"));
        u.setUserNm(rs.getString("USER_NM"));
        u.setPassword(rs.getString("PASSWORD"));
        u.setBgColor(rs.getString("BG_COLOR"));
        u.setTextColor(rs.getString("TEXT_COLOR"));
        u.setInsertDatetime(rs.getString("INSERT_DATETIME"));
        return u;
    }
}

์ด๊ฑฐ๋ž‘ ๋˜‘๊ฐ™์€ ๋œป์ด๋‹ค.

๋žŒ๋‹ค์— ๋Œ€ํ•œ ์„ค๋ช…์€ ์—ฌ๊ธฐ์—...

 

5๏ธโƒฃ ๊ฐ์ฒด ๋ฐ˜ํ™˜

SQL๋กœ๋ถ€ํ„ฐ ๋ฐ˜ํ™˜๋œ ๊ฐ์ฒด ๊ฐ’์„ userDetailsDTO์— ๋„ฃ์–ด์„œ ์›๋ž˜ ๋ฉ”์†Œ๋“œ UserDetailsDTO userDetails๋กœ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

 

[์ฐธ๊ณ  ์ž๋ฃŒ]

https://programmer93.tistory.com/68

 

Spring Security UserDetails, UserDetailsService ๋ž€? - ์‚ฝ์งˆ์ค‘์ธ ๊ฐœ๋ฐœ์ž

Spring Security - UserDetails , UserDetailsService UserDetails ๋ž€? Spring Security์—์„œ ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ๋‹ด๋Š” ์ธํ„ฐํŽ˜์ด์Šค์ด๋‹ค. Spring Security์—์„œ ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ ์œ„ํ•ด์„œ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๊ธฐ๋ณธ

programmer93.tistory.com

https://velog.io/@cyseok123/%EC%8B%9C%ED%81%90%EB%A6%AC%ED%8B%B0%EC%97%90-%EC%B6%94%EA%B0%80%ED%95%98%EA%B8%B0

 

[Spring] Spring-Security / UserDetails์™€ UserDetailsService ์ปค์Šคํ„ฐ๋งˆ์ด์ง•

UserDetails์™€ UserDetailsService ๋ฅผ ์ด์šฉํ•œ ์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•

velog.io