본문 바로가기
개발/Security

[SpringBoot] SecurityConfig - 동적 권한 체크

by 코딩하는 흰둥이 2024. 8. 2.

이전글

https://greed-yb.tistory.com/224

 

[SpringBoot] Security 로그인 인증, 인가(2) - SecurityConfig

이전글 https://greed-yb.tistory.com/223 [SpringBoot] Security 로그인 인증, 인가(1) - 환경설정 Java 17 Maven Spring Boot 3.0.3 Spring Security 3.0.4 Oracle 11g Mybatis IntelliJ Ultimate DBeaver Thymeleaf 폴더 구조 더보기 Security 한번

greed-yb.tistory.com

 

 

SecurityConfig 에서 권한이 있는지 확인할 때 hasAnyRole()에 있는 권한만 허용이 된다.

예) http.authorizeRequests().requestMatchers("/").hasAnyRole("권한1" , "권한2" , "권한3") 

 

권한을 관리하는 페이지가 있다면 하드코딩으로 관리 할 수 없기 때문에 방식을 추가하였다

 

 

 

권한 테이블의 데이터

 

import com.example.practice.security.handler.WebAccessDeniedHandler;
import com.example.practice.security.handler.WebAuthenticationEntryPoint;
import com.example.practice.service.role.RoleService;
import com.example.practice.vo.RoleVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;

import java.util.ArrayList;
import java.util.List;

@EnableWebSecurity
@Configuration
public class WebSecurityConfig {

    @Autowired
    private RoleService roleService;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

        // 권한 생성에 따른 role 추가
        List<RoleVo> vo = roleService.roleInfo();
        List<String> arrList = new ArrayList<>();

        for (int i = 0; i < vo.size(); i++) {
            arrList.add(String.valueOf(vo.get(i).getRoleId()));
        }
        String[] roleArray = arrList.toArray(new String[arrList.size()]);
        ////////


        http.csrf().disable(); // @EnableWebSecurity 이 csrf 공격을 방지하기 때문에 해당 기능을 disable로 변경
        http
                .authorizeRequests()
                .requestMatchers("/").hasAnyRole(roleArray) // 권한체크 - 내부적으로 ROLE_ 을 붙이기 때문에 ROLE_ 뒷부분만 적어준다
.......
.......
.......
.......
.......
.......

 

사용하던 쿼리를 그대로 사용하느라 List<RoleVo> 에서 List<String> 으로 작업을 두번하게 되었다

List<String> 으로 받아오길 바란다

 

 

 

 

 

 

AuthProvider

이전글

https://greed-yb.tistory.com/226

 

[SpringBoot] Security 로그인 인증, 인가(4) - AuthProvider

이전글 https://greed-yb.tistory.com/225 [SpringBoot] Security 로그인 인증, 인가(3) - handler 이전글 https://greed-yb.tistory.com/224 [SpringBoot] Security 로그인 인증, 인가(2) - SecurityConfig 이전글 https://greed-yb.tistory.com/223

greed-yb.tistory.com

권한을 확인하기 위해 코드가 수정되었다

 

import com.example.practice.service.user.UserService;
import com.example.practice.vo.UserVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

@Component
public class AuthProvider implements AuthenticationProvider {
    @Autowired
    private UserService userService;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = (String) authentication.getPrincipal();   // 로그인 Form에 name에 입력한  Id
        String password = (String) authentication.getCredentials(); // 로그인 Form에 name에 입력한 password

        PasswordEncoder passwordEncoder = userService.passwordEncoder();
        UsernamePasswordAuthenticationToken token;
        UserVo userVo = userService.getUserById(username);

        if (userVo != null && passwordEncoder.matches(password, userVo.getPassword())) { // 일치하는 user 정보가 있는지 확인
            List<GrantedAuthority> roles = new ArrayList<>();

            // 권한 부여
            roles.add(new SimpleGrantedAuthority(userVo.getRole()));

            // 인증된 user 정보를 token에 담는다
            token = new UsernamePasswordAuthenticationToken(userVo.getId(), null, roles);

            return token;
        }

        // 문제가 생겼을때 Exception을 반환하지 않으면 정상적으로 실행된 것으로 인식한다
        throw new BadCredentialsException("잘못된 정보입니다.");
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return true;
    }
}

 

 

 

service
@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    // 유저 정보
    public UserVo getUserById(String id) {
        return userMapper.getUserById(id);
    }
    
}

 

 

mapper.class
@Mapper
public interface UserMapper {

    /**
     * 유저 정보
     * @param username
     * @return
     */
    UserVo getUserById(String username);
    
}

 

 

mapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.example.practice.mapper.user.UserMapper">

    <!-- 회원 정보 가져오기 -->
    <select id="getUserById" resultType="com.example.practice.vo.UserVo">
        SELECT
            ID,
            PASSWORD,
            NAME,
            AGE,
            'ROLE_' || ROLE AS ROLE,
            ZIP_CODE,
            STREET_ADR,
            DETAIL_ADR,
            CREATE_TIME,
            ENABLED,
            SECURITY_NUMBER,
            PHONE_NUMBER,
            POSITION,
            DEPARTMENT,
            PROFILE
        FROM USERMEMBER
        WHERE id = #{username}
    </select>


</mapper>

mapper 에서 가져올 때 Role 에 "ROLE_" 을 붙여서 가져온다

 

 

 

권한이 추가삭제가 돼도 동적으로 권한을 체크할 수 있게 되었다

댓글