๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

Spring

Spring์˜ Security-UserDetails ๊ตฌํ˜„

UserDetails ๊ตฌํ˜„

Spring Security ๊ธฐ๋Šฅ์— ํ•„์š”ํ•œ UserDetails๋ฅผ ์•Œ์•„๋ณด๊ณ  ๊ตฌํ˜„ํ•ด๋ณด์ž.

Spring Security ๋กœ๊ทธ์ธ ํ•„ํ„ฐ๋ง

์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ์˜ ๋กœ๊ทธ์ธ ๊ณผ์ •์€ WebSecurityConfigurerAdapter์„ ๊ตฌํ˜„ํ•œ ํด๋ž˜์Šค์—์„œ ์ „๋ฐ˜์ ์ธ ์„ค์ •์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

์ด๋•Œ http.authorizeRequests()์˜ ๋ฉ”์„œ๋“œ ์ฒด์ธ ์ค‘ loginPage()์˜ ์ธ์ž๋กœ ๊ฒฝ๋กœ๋ฅผ ๋„ฃ์œผ๋ฉด ํ•ด๋‹น ๊ฒฝ๋กœ์˜ ๋กœ๊ทธ์ธ ์š”์ฒญ์„ ์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ๊ฐ€ ํ•„ํ„ฐ๋งํ•˜์—ฌ ๋กœ๊ทธ์ธ์ด ์ง„ํ–‰๋œ๋‹ค.

Spring Security Session

์Šคํ”„๋ง์€ ๋กœ๊ทธ์ธ์˜ ์ง„ํ–‰์ด ์ •์ƒ์ ์œผ๋กœ ์™„๋ฃŒ๋˜๋ฉด ์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ๋ฅผ ์œ„ํ•œ session์„ ๋งŒ๋“ค์–ด์ฃผ์–ด ๋กœ๊ทธ์ธ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ค€๋‹ค.

์ด session์€ ์›น ์„œ๋ฒ„์˜ ๊ฐ™์€ session ๊ณต๊ฐ„ ์† Security ContextHolder๋ผ๋Š” ํ‚ค๊ฐ’ ์•ˆ์— ์ €์žฅ๋œ๋‹ค.

Session์˜ ์˜ค๋ธŒ์ ํŠธ ํƒ€์ž… -> Authentication

์ด๋•Œ, ์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ ์„ธ์…˜์— ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ๋Š” ์˜ค๋ธŒ์ ํŠธ ํƒ€์ž…์€ Authentication ํƒ€์ž…์ด๋‹ค.

๊ทธ๋Ÿฌ๋ฏ€๋กœ, Authentication ํƒ€์ž… ์•ˆ์— ๋กœ๊ทธ์ธ์„ ํ•œ User์— ๋Œ€ํ•œ ์ •๋ณด๊ฐ€ ๋“ค์–ด ์žˆ์–ด์•ผ ํ•˜๋Š”๋ฐ, ์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ์ ์€ Authentication๋กœ ๊ฐ์Œ€ ์ˆ˜ ์žˆ๋Š” User์˜ ํƒ€์ž…์ด ๊ทธ๋ƒฅ User ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ์•„๋‹Œ UserDetails ํƒ€์ž…๋งŒ ๊ฐ€๋Šฅํ•˜๋‹ค.

UserDetails ๊ตฌํ˜„

์ด๋Ÿฌํ•œ ์œ„์˜ ๊ณผ์ • ๋•Œ๋ฌธ์— ์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ์˜ ๋กœ๊ทธ์ธ์—์„  UserDetails๋กœ User์— ๊ด€ํ•œ ์ •๋ณด๋ฅผ ์ „๋‹ฌํ•ด ์ค€๋‹ค.

์›ํ•˜๋Š” ์ •๋ณด๋ฅผ ๋‹ด๊ธฐ ์œ„ํ•ด UserDetails๋ฅผ ํ™•์žฅํ•œ ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•˜์—ฌ ๊ตฌํ˜„ํ•œ๋‹ค.

์ „์ฒด ๊ตฌํ˜„

package com.security.vividswan.auth;

import com.security.vividswan.model.User;
import org.springframework.security.core.GrantedAuthority;

import org.springframework.security.core.userdetails.UserDetails;

import java.util.ArrayList;
import java.util.Collection;

public class PrincipalDetails implements UserDetails {
    private User user; // composition

    PrincipalDetails(User user){
        this.user = user;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        Collection<GrantedAuthority> collect = new ArrayList<>();
        collect.add(new GrantedAuthority() {
            @Override
            public String getAuthority() {
                return user.getRole();
            }
        });
        return collect;
    }

    @Override
    public String getPassword() {
        return user.getPassword();
    }

    @Override
    public String getUsername() {
        return user.getUsername();
    }

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

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

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

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

์ฝ”๋“œ ์„ค๋ช…

    private User user; // composition

    PrincipalDetails(User user){
        this.user = user;
    }

์›ํ•˜๋Š” user ์ •๋ณด๋ฅผ ๋‹ด์•„์ฃผ๊ธฐ ์œ„ํ•ด User ๊ฐ์ฒด๋ฅผ ์ปดํฌ์ง€์…˜ํ•œ๋‹ค.

์ด ํด๋ž˜์Šค๋Š” new ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด Authentication์—์„œ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๋ฏ€๋กœ ๋”ฐ๋กœ ์–ด๋…ธํ…Œ์ด์…˜์„ ํ•ด์ฃผ์ง€ ์•Š๋Š”๋‹ค.

์ด๋ฅผ ์œ„ํ•ด User ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ๋“ค์–ด๊ฐ€๋Š” ์ƒ์„ฑ์ž๋ฅผ ๋งŒ๋“ ๋‹ค.

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        Collection<GrantedAuthority> collect = new ArrayList<>();
        collect.add(new GrantedAuthority() {
            @Override
            public String getAuthority() {
                return user.getRole();
            }
        });
        return collect;
    }

User์˜ Role์„ ๋„ฃ์–ด์ค˜์•ผ ํ•˜๋Š” getAuthorities() ๋ฉ”์„œ๋“œ๋‹ค.

ํ•œ ๋ช…์˜ User์˜ Role์ด ๋ณต์ˆ˜์ผ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ Collection ํ˜•์‹์ธ๋ฐ <GrantedAuthority>์˜ ์ œ๋„ค๋ฆญ์„ ๋”ฐ๋ผ์ค˜์•ผ ํ•œ๋‹ค.

ํ•„์š”ํ•œ ์ œ๋„ค๋ฆญ์„ ๋”ฐ๋ฅด๋Š” ArrayList๋ฅผ ๋งŒ๋“ค์–ด์„œ ๋ฆฌ์ŠคํŠธ์— ์˜ค๋ธŒ์ ํŠธ๋ฅผ ๋„ฃ์–ด์ค˜์•ผ ํ•œ๋‹ค.

์ด๋•Œ GrantedAuthority ํ˜•์‹์„ ์ง€ํ‚ค๊ธฐ ์œ„ํ•ด new GrantedAuthority()๋กœ ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

getAuthority()๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋“œ ํ•ด์ค˜์•ผ ํ•˜๋Š”๋ฐ ์ด๋•Œ User์˜ Role์„ String ํ˜•์‹์œผ๋กœ ๋ฆฌํ„ดํ•˜๋ฉด ๋ฆฌ์ŠคํŠธ์— ์˜ค๋ธŒ์ ํŠธ ์‚ฝ์ž…์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

    @Override
    public String getPassword() {
        return user.getPassword();
    }

    @Override
    public String getUsername() {
        return user.getUsername();
    }

get๊ณผ ๊ด€๋ จ๋œ ๋ฉ”์„œ๋“œ์—” User์˜ ์ •๋ณด๋ฅผ return ํ•ด์ค€๋‹ค.

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

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

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

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

๊ฐ€์ž…๋œ User์— ๋Œ€ํ•œ ๊ธฐ๊ฐ„ ๋งŒ๋ฃŒ, ์ž ๊ธˆ ์ƒํƒœ ๋“ฑ๋“ฑ์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฉ”์„œ๋“œ๋‹ค.

์œ„์˜ ์˜ˆ์ œ์—์„  ๋ชจ๋‘ true ์ฒ˜๋ฆฌํ–ˆ์ง€๋งŒ ํ•„์š”ํ•œ ์กฐ๊ฑด๋“ค์„ ๋งŒ๋“ค๊ณ  ๋ถ„๊ธฐ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.