본문 바로가기
Java/spring

spring security를 알아보자 - 5

by 티코딩 2024. 3. 21.

UserDetailsManager를 구현하는클래스를 알아보자.

 

ㅇ InMemoryUserDetailsManager

 

public void createUser(UserDetails user) {
        Assert.isTrue(!this.userExists(user.getUsername()), "user should not exist");
        this.users.put(user.getUsername().toLowerCase(), new MutableUser(user));
    }

    public void deleteUser(String username) {
        this.users.remove(username.toLowerCase());
    }

    public void updateUser(UserDetails user) {
        Assert.isTrue(this.userExists(user.getUsername()), "user should exist");
        this.users.put(user.getUsername().toLowerCase(), new MutableUser(user));
    }

    public boolean userExists(String username) {
        return this.users.containsKey(username.toLowerCase());
    }

    public void changePassword(String oldPassword, String newPassword) {
        Authentication currentUser = this.securityContextHolderStrategy.getContext().getAuthentication();
        if (currentUser == null) {
            throw new AccessDeniedException("Can't change password as no Authentication object found in context for current user.");
        } else {
            String username = currentUser.getName();
            this.logger.debug(LogMessage.format("Changing password for user '%s'", username));
            if (this.authenticationManager != null) {
                this.logger.debug(LogMessage.format("Reauthenticating user '%s' for password change request.", username));
                this.authenticationManager.authenticate(UsernamePasswordAuthenticationToken.unauthenticated(username, oldPassword));
            } else {
                this.logger.debug("No authentication manager set. Password won't be re-checked.");
            }

            MutableUserDetails user = (MutableUserDetails)this.users.get(username);
            Assert.state(user != null, "Current user doesn't exist in database.");
            user.setPassword(newPassword);
        }
    }

    public UserDetails updatePassword(UserDetails user, String newPassword) {
        String username = user.getUsername();
        MutableUserDetails mutableUser = (MutableUserDetails)this.users.get(username.toLowerCase());
        mutableUser.setPassword(newPassword);
        return mutableUser;
    }

    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        UserDetails user = (UserDetails)this.users.get(username.toLowerCase());
        if (user == null) {
            throw new UsernameNotFoundException(username);
        } else {
            return new User(user.getUsername(), user.getPassword(), user.isEnabled(), user.isAccountNonExpired(), user.isCredentialsNonExpired(), user.isAccountNonLocked(), user.getAuthorities());
        }
    }

 

users는 hashmap으로 키-값 형태로 저장되는데, 키에는 유저네임이 저장되고, 값에는 유저에대한 정보가 들어간다.

loadUserByUsername() 메서드에서는 인메모리상에서 유저를 찾게된다.

 

ㅇ JdbcUserDetailsManager

하지만 우린 데이터베이스에서 유저를 찾는상황이 더 많을것이다. JdbcUserDetailsManager은 데이터베이스에서 유저를 불러와서 가공할때 사용된다. 

public void createUser(final UserDetails user) {
        this.validateUserDetails(user);
        this.getJdbcTemplate().update(this.createUserSql, (ps) -> {
            ps.setString(1, user.getUsername());
            ps.setString(2, user.getPassword());
            ps.setBoolean(3, user.isEnabled());
            int paramCount = ps.getParameterMetaData().getParameterCount();
            if (paramCount > 3) {
                ps.setBoolean(4, !user.isAccountNonLocked());
                ps.setBoolean(5, !user.isAccountNonExpired());
                ps.setBoolean(6, !user.isCredentialsNonExpired());
            }

        });
        if (this.getEnableAuthorities()) {
            this.insertUserAuthorities(user);
        }

    }

    public void updateUser(final UserDetails user) {
        this.validateUserDetails(user);
        this.getJdbcTemplate().update(this.updateUserSql, (ps) -> {
            ps.setString(1, user.getPassword());
            ps.setBoolean(2, user.isEnabled());
            int paramCount = ps.getParameterMetaData().getParameterCount();
            if (paramCount == 3) {
                ps.setString(3, user.getUsername());
            } else {
                ps.setBoolean(3, !user.isAccountNonLocked());
                ps.setBoolean(4, !user.isAccountNonExpired());
                ps.setBoolean(5, !user.isCredentialsNonExpired());
                ps.setString(6, user.getUsername());
            }

        });
        if (this.getEnableAuthorities()) {
            this.deleteUserAuthorities(user.getUsername());
            this.insertUserAuthorities(user);
        }

        this.userCache.removeUserFromCache(user.getUsername());
    }

    private void insertUserAuthorities(UserDetails user) {
        Iterator var2 = user.getAuthorities().iterator();

        while(var2.hasNext()) {
            GrantedAuthority auth = (GrantedAuthority)var2.next();
            this.getJdbcTemplate().update(this.createAuthoritySql, new Object[]{user.getUsername(), auth.getAuthority()});
        }

    }

    public void deleteUser(String username) {
        if (this.getEnableAuthorities()) {
            this.deleteUserAuthorities(username);
        }

        this.getJdbcTemplate().update(this.deleteUserSql, new Object[]{username});
        this.userCache.removeUserFromCache(username);
    }

 

정말 많은 메서드가 여기 있다. 이메서드 위에 쿼리가 잘 정리되어있어서 이메서드들을 호출할때 자동으로 쿼리가 불러와져서 데이터베이스내에서 데이터들을 불러 올 수있고 수정할수도 있다.

 

ㅇ DB세팅

MySql을 노트북 내에 설치해서 사용해도되지만, 데이터베이스를 클라우드에 두는 방법이 있다. RDS에 MySQL로 데이터베이스를 하나 만들고 연결시켰다.

그리고 쿼리로 테이블들을 만들어줬다.

그리고 pom.xml파일에

<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>
		<dependency>
			<groupId>com.mysql</groupId>
			<artifactId>mysql-connector-j</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>

이렇게 넣어주고, 다음은 application.properties에 아래와같이 넣어줬다.

spring.datasource.url=jdbc:mysql://springsecurity.ce0eox1y1obm.us-east-1.rds.amazonaws.com/bank
spring.datasource.username=admin
spring.datasource.password=MySQLSpringSecurity
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

 

그리고 SecurityConfig에 지난 InMemoryUserDetailsManager 관련코드는 주석처리하고 Jdbc를 사용해야하니

@Bean
public UserDetailsService userDetailsService(DataSource dataSource) {
    return new JdbcUserDetailsManager(dataSource);
}


이렇게넣어줬다.

 

이렇게 넣어주고 테스트해보면 데이터베이스에 잘 뜨는걸 볼 수 있다.

'Java > spring' 카테고리의 다른 글

spring security를 알아보자 - 7  (0) 2024.03.26
spring security를 알아보자 - 6  (0) 2024.03.25
spring security를 알아보자 - 4  (0) 2024.03.18
spring security를 알아보자 - 3  (0) 2024.03.15
spring security를 알아보자 - 2  (0) 2024.03.12