Home 관리자 권한, 메뉴 관리 (3)
Post
Cancel

관리자 권한, 메뉴 관리 (3)

user_menu_authority


  • 이전에 작성한 구성 정보를 가지고 spring security적용하여 메뉴별 CRUD권한 체크와 로그인 사용자의 접근 가능한 메뉴정보를 가져오는 기능을 작성해 보려 합니다. 이를 통해 가지고 있는 권한에 맞는 메뉴와 CRUD권한별 인가 설정을 할 수 있게 되었습니다.


spring security config 설정

  • spring security config 설정 정보 입니다.
    • securityFilterChain()메소드 안에 들어가있는 메소드 들은 의존주입 받은 httpSecurity를 이용하여 각 메소드별로 별개의 설정을 하게 하여 메소드명만으로도 구성정보를 쉽게 알아볼 수 있게 하였습니다.
      • 이번 포스팅에서는 securityFilterChain()안에있는 구성 정보중 authenticationProviderConfig()구성만 살펴보겠습니다.
    • @EnableMethodSecurity를 적용하여 컨트롤러(메소드)별로 접근 권한을 설정하게 하였습니다.
    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      
      @Slf4j
      @Configuration
      @EnableMethodSecurity
      @RequiredArgsConstructor
      public class WebSecurityConfig {
      
          private final HttpSecurity httpSecurity;
      
          @Bean
          public SecurityFilterChain securityFilterChain() throws Exception {
              corsConfig();
              csrfConfig();
              headerConfig();
              authorizeHttpRequestsConfig();
              formLoginConfig();
              oAuth2LoginConfig();
              logOutConfig();
              exceptionHandlingConfig();
              authenticationProviderConfig();
              return httpSecurity.build();
          }
      
      }
      


User

  • User엔티티 클래스 입니다. 로그인한 사용자의 정보를 해당 엔티티로 구성하여 인증 공급자를 거쳐 SecurityContextHodler안에서 관리되게 됩니다. 로그인한 유저의 메뉴별 CURD 권한 리스트와, 메뉴 리스트를 포함하고 있습니다.
    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      
      @Getter
      @ToString
      @NoArgsConstructor
      public class User implements UserDetails {
      
          private String userId;
          private String password;
          private String userType;
          private List<BackOfficeMenu> userMenuAuthorityList;
          private List<BackOfficeMenuRes> userMenuAuthorityResList;
      
          @Override
          public Collection<? extends GrantedAuthority> getAuthorities() {
              return userMenuAuthorityList.stream()
                      .map(BackOfficeMenu::getMenuAuthorityId)
                      .map(SimpleGrantedAuthority::new)
                      .toList();
          }
      
          public void loginUserMenuList(List<BackOfficeMenuRes> backOfficeMenuRes){
              this.userMenuAuthorityResList = backOfficeMenuRes;
          }
      
          ...
      
      }
      
      • getAuthorities() 부분에서 가져온 BackOfficeMenu에서 메뉴 권한 부분을 권한 리스트로 설정해줍니다. 작성하다 느낀건데 BackOfficeMenu클래스의 이름이 마음에 안드는군요. todo 목록으로 해당 클래스명을 BackOfficeMenuAuthority로 변경한다. 라고 기록후 넘어가겠습니다.


  • mybatis 코드 입니다. 쿼리된 결과를 User엔티티에 매핑시켜줍니다.
    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      
      <resultMap id="user" type="User">
              <result property="userId" column="userId"/>
              <result property="password" column="password"/>
              <result property="userType" column="userType"/>
      
              <collection property="userMenuAuthorityList" ofType="BackOfficeMenu">
                  <result property="menuAuthorityId" column="menuAuthorityId"/>
                  <result property="menuId" column="menuId"/>
                  <result property="name" column="name"/>
                  <result property="depth" column="depth"/>
                  <result property="reference" column="reference"/>
                  <result property="menuOrder" column="menuOrder"/>
                  <result property="createDate" column="createDate"/>
                  <result property="createId" column="createId"/>
                  <result property="updateDate" column="updateDate"/>
                  <result property="updateId" column="updateId"/>
              </collection>
      
          </resultMap>
      
          <sql id="selectUserInfoBasicSql">
              SELECT b.menu_authority_id AS "menuAuthorityId",
                     e.user_id           AS "userId",
                     e.password          AS "password",
                     e.user_type         AS "userType",
                     d.menu_id           AS "menuId",
                     d.name              AS "name",
                     d.depth             AS "depth",
                     d.reference         AS "reference",
                     d.menu_order        AS "menuOrder",
                     d.create_date       AS "createDate",
                     d.create_id         AS "createId",
                     d.update_date       AS "updateDate",
                     d.update_id         AS "updateId"
              FROM common_code a
                       INNER JOIN user_type_menu_authority b ON b.common_code_id = a.common_code_id
                       INNER JOIN menu_authority c ON b.menu_authority_id = c.menu_authority_id
                       INNER JOIN menu d ON d.menu_id = c.menu_id
                       INNER JOIN "user" e ON e.user_type = a.common_code_id
              WHERE 1 = 1
          </sql>
      
          <select id="selectUserByUserIdAndPassword" resultMap="user">
              <include refid="selectUserInfoBasicSql"/>
              AND e.user_id = #{userId}
              AND e.password = #{password}
          </select>
      
          <select id="selectUserByUserId" resultMap="user">
              <include refid="selectUserInfoBasicSql"/>
              AND e.user_id = #{userId}
          </select>
      


  • mybatisresultMap이 의도한대로 User엔티티에 바인딩이 되는지 간단한 테스트를 통해 직관해 보도록 하겠습니다.
    • @MybatisTest를 이용하여 매퍼 테스트를 진행하였고 나머지 설명은 생략하겠습니다.
      • ObjectMapper의 경우 전체 스프링 Bean을 끌어오는게 아니라 주입이 되지 않아 직접 생성하여 사용하였습니다. 객체를 생성하여 테스트 하던 중에 ObjectMapper에서 LocalDateTime의 형변환이 안되어 추가적으로 @BeforeEach에서 형변환이 가능하게 해주는 모듈을 추가 설정 해주었습니다.
    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      
      @Slf4j
      @MybatisTest
      @ActiveProfiles("local")
      @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
      class UserMapperTest {
      
          @Autowired
          private UserMapper userMapper;
      
          private final ObjectMapper objectMapper = new ObjectMapper();
      
          @BeforeEach
          void setup() {
              objectMapper.registerModule(new JavaTimeModule());
          }
      
          @Test
          void selectUserByUser() throws Exception {
              Optional<User> admin = userMapper.selectUserByUserIdAndPassword("ad_sub_admin", "1234");
              Assertions.assertTrue(admin.isPresent());
              User user = admin.get();
              Assertions.assertNotNull(user);
              log.info("user info = {}", objectMapper.writeValueAsString(user));
          }
      
      }
      
      • 유저 정보를 JSON형태로 출력하였고 아래는 그 결과입니다.
        • result


  • 다음 포스팅에서는 AuthenticationProvider구성과 그 이후 설정들을 작성해보겠습니다.
This post is licensed under CC BY 4.0 by the author.