[Spring] Spring Security ์ธ์ฆ ์ ˆ์ฐจ Interface | UserDetails์™€ UserDetailsService

2022. 3. 29. 08:00ใ†Back-End ์ž‘์—…์‹ค/Spring Framework

728x90
๋ฐ˜์‘ํ˜•

 

๐Ÿš€ UserDetails & UserDetailsService๋ž€?

    ๐Ÿ”ฝ  ๊ฐœ์š”

UserDetailsService Interface๋Š” Data Base์—์„œ User ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์—ญํ• ์„ ํ•˜๋Š” ๊ฒƒ์ด์—์š”.

ํ•ด๋‹น Interface์˜ Method์—์„œ Data Base User ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์™€์„œ AuthenticationProvider Interface๋กœ User ์ •๋ณด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด ๊ทธ ๊ณณ์—์„œ ์ด์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ์ •๋ณด์™€ DB์— ์žˆ๋Š” ํšŒ์› ์ •๋ณด๋ฅผ ๋น„๊ตํ•˜๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด์—์š”. DB์—์„œ ํšŒ์› ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์ž‘์—…์— ํ•„์š”ํ•œ Interface๋Š” UserDetails์™€ UserDetilasService Interface์ธ ๊ฒƒ์ด์—์š”.

 

 

 

    ๐Ÿ”ฝ  UserDetails

Spring Security์—์„œ ์ด์šฉ์ž์˜ ์ •๋ณด๋ฅผ ๋‹ด๋Š” Interface๋Š” UserDetails Interface์ธ ๊ฒƒ์ด์—์š”. ์ด Interface๋ฅผ ๊ตฌํ˜„ํ•˜๊ฒŒ ๋˜๋ฉด Spring Security์—์„œ ๊ตฌํ˜„ํ•œ Class๋ฅผ ํ†ตํ•ด ์ด์šฉ์ž ์ •๋ณด๋ฅผ ์ธ์‹ํ•˜๊ณ , ์ธ์ฆ ์ž‘์—…์„ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด์—์š”.

UserDetails Interface๋Š” VO(Value Object)์˜ ์—ญํ• ์„ ํ•œ๋‹ค๊ณ  ๋ณด๋ฉด ๋˜๊ณ , ์ด๋ฅผ ํ†ตํ•ด ์ด์šฉ์ž ์ •๋ณด๋ฅผ ๋ชจ๋‘ ๋‹ด์•„๋‘๋Š” ๊ฐ์ฒด๋กœ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด์—์š”.

UserDetails Interface๋ฅผ ๊ตฌํ˜„ํ•˜๊ฒŒ ๋˜๋ฉด Override ๋˜๋Š” Method๋“ค์ด ์žˆ๋Š” ๊ฒƒ์ด์—์š”. ์ด Method๋“ค์„ ๋จผ์ € ํŒŒ์•…ํ•˜๋Š” ๊ฒŒ ์•„๋ฌด๋ž˜๋„ ์ข‹์„ ๊ฑฐ ๊ฐ™์•„์š”.

๋˜ํ•œ, ํšŒ์› ์ •๋ณด์— ๊ด€ํ•œ ๋‹ค๋ฅธ ์ •๋ณด(์ด๋ฆ„, ๋‚˜์ด, ์ƒ๋…„์›”์ผ ๋“ฑ๋“ฑ..)๋„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด์—์š”.

Override๋œ Method๋“ค๋งŒ Spring Security์—์„œ ์•Œ์•„์„œ ์ด์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋”ฐ๋กœ Class๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๊ณ , Member ๋ณ€์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•ด์„œ ๊ฐ™์ด ์‚ฌ์šฉํ•ด๋„ ์ข‹์€ ๊ฒƒ์ด์—์š”.

๊ทธ๋ฆฌ๊ณ , MyBatis๋ฅผ ์ด์šฉํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด ์—ฌ๊ธฐ์— Member ๋ณ€์ˆ˜๋“ค์— ๋งž๋Š” getter, setter๋ฅผ ๋งŒ๋“ค์–ด ์ฃผ๋ฉด ๋˜๋Š” ๊ฒƒ์ด์—์š”.

 

Method Return Type Detail
getAuthorities() Collections<? extends GrantedAuthority> ์ด์šฉ์ž ๊ณ„์ •์ด ๊ฐ–๊ณ  ์žˆ๋Š” ๊ถŒํ•œ ๋ชฉ๋ก ๋ฐ˜ํ™˜
getPassword() String ์ด์šฉ์ž ๊ณ„์ •์˜ ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ฐ˜ํ™˜
getUsername() String ์ด์šฉ์ž ๊ณ„์ •์˜ ์ด๋ฆ„(ID)๋ฅผ ๋ฐ˜ํ™˜
isAccountNonExpired() boolean ์ด์šฉ์ž ๊ณ„์ • ๋งŒ๋ฃŒ ์—ฌ๋ถ€ ๋ฐ˜ํ™˜
true : ๋งŒ๋ฃŒ ๋˜์ง€ ์•Š์Œ
false : ๋งŒ๋ฃŒ
isAccountNonLocked() boolean ์ด์šฉ์ž ๊ณ„์ • ์ž ๊ธˆ ์—ฌ๋ถ€ ๋ฐ˜ํ™˜
true : ์ž ๊ธฐ์ง€ ์•Š์Œ
false : ์ž ๊น€
isCredentialNonExpired() boolean ๋น„๋ฐ€๋ฒˆํ˜ธ ๋งŒ๋ฃŒ ์—ฌ๋ถ€ ๋ฐ˜ํ™˜
true : ๋งŒ๋ฃŒ ๋˜์ง€ ์•Š์Œ
false : ๋งŒ๋ฃŒ
isEnable() boolean ๊ณ„์ • ํ™œ์„ฑํ™”(์‚ฌ์šฉ ๊ฐ€๋Šฅ) ์—ฌ๋ถ€ ๋ฐ˜ํ™˜
true : ํ™œ์„ฑํ™” (์ด์šฉ ๊ฐ€๋Šฅ)
false : ๋น„ ํ™œ์„ฑํ™”  (์ด์šฉ ๋ถˆ๊ฐ€)

`getUsername()`์€ ๊ณ„์ •์˜ ์ด๋ฆ„(ID)๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š”๋ฐ, ๊ทธ ๋ง์ธ ์ฆ‰, ์šฐ๋ฆฌ๊ฐ€ Login ํ•  ๋•Œ ์ด์šฉํ•˜๋Š” ID ํ˜น์€ E-mail์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์ด์—์š”. ๊ทธ๋ฆฌ๊ณ , ๊ณ„์ •์ด ๋งŒ๋ฃŒ ๋˜์—ˆ๋Š”์ง€ ํ˜น์€ ๊ณ„์ •์ด ์ž ๊ฒจ ์žˆ๋Š”์ง€ ๋“ฑ์— ๋Œ€ํ•ด ํ™•์ธํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๋ฉด ๋ฌด์กฐ๊ฑด true๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ํ•ด ์ฃผ๋ฉด ๋˜๋Š” ๊ฒƒ์ด์—์š”. ๋งŒ์•ฝ ํ™•์ธํ•  Member ๋ณ€์ˆ˜๊ฐ€ ์žˆ๋‹ค๋ฉด ๊ทธ Member ๋ณ€์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•ด ์ฃผ๋ฉด ๋˜๋Š” ๊ฒƒ์ด์—์š”.

์•„๋ž˜ ์˜ˆ์‹œ๋Š” ๊ณ„์ •์˜ ํ™œ์„ฑ / ๋น„ํ™œ์„ฑํ™”๋ฅผ ํ™•์ธํ•˜๋Š” Member ๋ณ€์ˆ˜๊ฐ€ ์กด์žฌํ•˜๊ณ , ์ด ๋•Œ๋ฌธ์— `isEnable()`์€ ํ•ด๋‹น Member ๋ณ€์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ ํ•ด ์ฃผ๊ฒŒ ํ•œ ๊ฒƒ์ด์—์š”.

 

์˜ˆ์‹œ ์ฝ”๋“œ

@SuppressWarnings("serial")
public class CustomUserDetails implements UserDetails {
    
    private String id;
    private String password;
    private String authority;
    private boolean enabled;
    private String name;
    
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        ArrayList<GrantedAuthority> auth = new ArrayList<GrantedAuthority>();
        auth.add(new SimpleGrantedAuthority(AUTHORITY));
        return auth;
    } // getAuthorities() ๋
 
    @Override
    public String getPassword() {
        return password;
    }
 
    @Override
    public String getUsername() {
        return id;
    }
 
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }
 
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }
 
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }
 
    @Override
    public boolean isEnabled() {
        return enabled;
    }
    
    public String getNAME() {
        return NAME;
    }
 
    public void setNAME(String name) {
        this.name = name;
    }
 
} // class ๋

 

CustomUserDetails - Member ๋ณ€์ˆ˜

 

์œ„์˜ ๊ทธ๋ฆผ๊ณผ ๊ฐ™์ด ์ด์šฉ์ž ์ •๋ณด๋“ค์˜ Member ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•ด ์ค„ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด์—์š”. ๋” ๋งŽ์€ ์ •๋ณด๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋ฉด ์ถ”๊ฐ€๋ฅผ ํ•ด๋„ ๋ฉ๋‹ˆ๋‹ค.

 

CustomUserDetails - getAuthorities()

๋ฐ˜์‘ํ˜•

 

์œ„ ๊ทธ๋ฆผ์˜ Method๋Š” ๊ณ„์ •์ด ๊ฐ–๊ณ  ์žˆ๋Š” ๊ถŒํ•œ ๋ชฉ๋ก์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ์นœ๊ตฌ์ธ ๊ฒƒ์ด์—์š”.

์œ„์˜ `SimpleGrantedAutority()`๋Š” `GrantedAuthority`๋ฅผ Implementํ•œ Class์ธ๋ฐ, `basic concrete implementations of a GrantedAuthority stores a String representation of an authority granted to the authentication object` ๊ถŒํ•œ์„ `String`์œผ๋กœ ๋ฐ˜ํ™˜ํ•ด ์ฃผ๋Š” ์นœ๊ตฌ์ธ ๊ฒƒ์ด์—์š”.

๊ฒฐ๊ตญ ๊ถŒํ•œ ๋ชฉ๋ก์„ ๋ฌธ์ž์—ด๋กœ ์–ป๊ธฐ ์œ„ํ•ด ์œ„์˜ Method๋ฅผ ์ด์šฉํ•˜๋Š” ๊ฒƒ์ด์—์š”.

 

 

CustomUserDetails - isEnabled()

์ด์šฉ์ž ๊ณ„์ •์— ํ™œ์„ฑ / ๋น„ํ™œ์„ฑํ™” ์—ฌ๋ถ€๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด Member ๋ณ€์ˆ˜๋กœ ์„ ์–ธํ•œ `enabled`๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์ด์—์š”.

 

 

 

 

 

 

    ๐Ÿ”ฝ  UserDetailsService

        ๐Ÿ“ฆ DevInquryReplyVO.java

์ด์šฉ์ž ์ •๋ณด๋ฅผ ๋‹ด์€ ๊ฐ์ฒด๋ฅผ `UserDetails`๋ฅผ ๊ตฌํ˜„ํ•ด์„œ ๋งŒ๋“ค์—ˆ๋‹ค๋ฉด Data Base์—์„œ ์ด์šฉ์ž ์ •๋ณด๋ฅผ ์ง์ ‘ ๊ฐ€์ ธ์˜ค๋Š” Interface ๋˜ํ•œ ๊ตฌํ˜„ ํ•ด ์ฃผ์–ด์•ผ ํ•˜๋Š” ๊ฒƒ์ด์—์š”.

`UserDetailsService` Interface๋Š” JPA๋‚˜, MyBatis๋ฅผ ๊ตฌํ˜„ํ•œ Class ๋“ฑ์„ ํ†ตํ•ด Data Base์—์„œ ์ด์šฉ์ž ์ •๋ณด๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์•„์ฃผ ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•˜๋Š” ์นœ๊ตฌ๊ฐ€ ์กด์žฌํ•˜๋Š”๋ฐ, ๊ทธ ์นœ๊ตฌ๊ฐ€ ๋ฐ”๋กœ `loadUserByUsername()`์ธ ๊ฒƒ์ด์—์š”. ์ด ์นœ๊ตฌ๋Š” ์ด์šฉ์ž ์ •๋ณด๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ž‘์—…์„ ํ•˜๋ฉด ๋˜๋Š” ๊ฒƒ์ด์—์š”.

`UserDetailsService` Interface๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉด `loadUserByUsername()`๋ฅผ Overrideํ•ด์„œ ์ด์šฉํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์ด์—์š”. ์—ฌ๊ธฐ์—์„œ CustomUserDetails ํ˜•์œผ๋กœ ์ด์šฉ์ž์˜ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋ฉด ๋˜๋Š” ๊ฒƒ์ด์—์š”. ๊ฐ€์ ธ์˜จ ์ด์šฉ์ž ์ •๋ณด๊ฐ€ ์žˆ๋‹ค? ์—†๋‹ค?์— ๋”ฐ๋ผ ์˜ˆ์™ธ์™€ ์ด์šฉ์ž ์ •๋ณด๋ฅผ ๋ฐ˜ํ™˜ํ•ด์ฃผ๋ฉด ๋˜๋Š” ๊ฒƒ์ด์—์š”.

 

์˜ˆ์‹œ ์ฝ”๋“œ

public class CustomUserDetailsService implements UserDetailsService {
    
    @Autowired
    private UserAuthDAO userAuthDAO;
 
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        CustomUserDetails user = userAuthDAO.getUserById(username);
        if(user==null) {
            throw new UsernameNotFoundException(username);
        }
        return user;
    } // loadUserByUsername(String username) ๋
} // class ๋

 

์œ„์˜ Code์—์„œ `loadUserByUsername()` Body๋ฅผ ๋ณด๋ฉด DAO์˜ `getUserById()`๋ฅผ ํ˜ธ์ถœํ•˜๋Š”๋ฐ, ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋“ค์–ด์˜จ username(์ด์šฉ์ž ID)๋ฅผ ๋„ฃ์–ด์ฃผ์–ด DB์—์„œ ๊ฒ€์ƒ‰์„ ํ•œ ๋’ค ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ์œ„์—์„œ `UserDatils`๋ฅผ ๊ตฌํ˜„ํ•œ ๊ตฌํ˜„์ฒด `CustomUserDetails` ๊ฐ์ฒด ์ž๋ฃŒํ˜• user ๋ณ€์ˆ˜๋กœ ๋ฐ›์•„ ์ฃผ๋Š” ๊ฒƒ์ด์—์š”.

๋งŒ์•ฝ user ์ •๋ณด๋ฅผ ๋ชป ์ฐพ์•˜๋‹ค๋ฉด Login์„ ํ•  ์ˆ˜ ์—†๋Š” ๊ฒƒ์ด๊ณ , ๊ทธ๋ ‡๋‹ค๋ฉด `UsernameNotFoundException()`์ด ํ„ฐ์ง€๋„๋ก ๋˜์–ด์žˆ๊ณ , ์กด์žฌํ•œ๋‹ค๋ฉด ํšŒ์› ์ •๋ณด๋ฅผ ๋ฐ˜ํ™˜ ํ•ด ์ฃผ๋ฉด ๋˜๋Š” ๊ฒƒ์ด์—์š”.

 

 

 

์ฐธ๊ณ  Site : https://writerroom.tistory.com/211

 

 

 

 

 

 

 

 

 

 

728x90
๋ฐ˜์‘ํ˜•