Post

Spring Boot: 시큐리티(Security) – 5 – 권한별 접근 가능한 페이지를 데이터베이스에 설정하기 (동적 설정)

[rcblock id=”3197”]

깃허브에서 전체 코드 보기 - https://github.com/ayaysir/spring-boot-security-example-1

 

스프링 부트 시큐리티에서 자주 변경되는 정보를 분리하는 방법에 대해 알아보겠습니다. (참고 블로그)

 

 

Security Config 클래스의 코드에서 위의 빨간색 네모 코드를 데이터베이스에서 가져오는 것으로 바꾸는 작업을 하겠습니다. 이유는 위 네모박스는 자주 변경될 수 있는 부분인데 하드코딩 방식으로 정보가 입력되어 있기 때문입니다.

 

참고로 컨트롤러(일부)는 다음과 같습니다.

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
@ResponseBody
@RequestMapping("/adminOnly")
public String adminOnly(Authentication auth) {
  return "Secret Page!!" 
      + "<br>my roles: "+ auth.getAuthorities().toString();
}

@ResponseBody
@RequestMapping("/userOnly")
public String userOnly(Authentication auth) {
  return "USER ONLY"
      + "<br>my roles: "+ auth.getAuthorities().toString();
}

@ResponseBody
@RequestMapping("/userOnly/{sub}")
public String userOnlySub(Authentication auth, @PathVariable("sub") String sub) {
  return "USER ONLY SUB PAGE (" + sub + ")"
      + "<br>my roles: "+ auth.getAuthorities().toString();
}

@ResponseBody
@RequestMapping("/everybodyOK")
public String everybodyOK() {
  return "EVERYBODY OK";
}

 

1. 데이터베이스에서 테이블 생성 및 URL, 권한정보를  입력합니다.

프로젝트에 연결되어 있는 DB를 이용해 정보를 입력하면 됩니다. 여기서는 mariadb를 사용하였습니다.

 

2. 위의 데이터베이스를 가져오는 DAO 등을 작성합니다.
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
package com.springboot.security.dao;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class SecurityDAO {
  @Autowired JdbcTemplate jt;
  
  public List<Map<String, Object>> getAuthReq() {
    return jt.query("select * from security_authreq", (rs, rowNum) -> {
      Map<String, Object> aRow = new HashMap<>();
      aRow.put("id", rs.getInt(1));
      aRow.put("url", rs.getString(2));
      aRow.put("hasAuthority", rs.getString(3));
      aRow.put("date", rs.getString(4));
      return aRow;
    });
  }

}

 

3. Security Config 클래스 파일에서 하드코딩에 해당하는 부분을 별도 메소드로 교체하고, DB에서 읽어오도록 변경합니다.
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
53
54
55
56
57
58
59
(.......)

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  @Autowired
  private DataSource dataSource;

  @Autowired private SecurityDAO sd;

  @Override
  protected void configure(HttpSecurity http) throws Exception {

    setAntMatchers(http, "ROLE_");

    http.csrf().disable()
    // setAntMatchers 메소드로 대체되었음
    .formLogin().loginPage("/login").failureUrl("/login?error").permitAll()
    .and()
    .logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
    .addLogoutHandler(new TaskImplementingLogoutHandler()).permitAll().logoutSuccessUrl("/");

  }

  (.......)

  protected void setAntMatchers(HttpSecurity http, String rolePrefix) throws Exception {
    List<Map<String, Object>> list = sd.getAuthReq();
    System.out.println(list);
    for(Map<String, Object> m : list) {
      // 쉼표(,)로 구분된 권한 정보를 분리 후 배열로 저장
      String[] roles = m.get("hasAuthority").toString().split(",");

      // 권한 앞에 접두사(rolePrefix) 붙임
      for(int i = 0; i < roles.length; i++) {
        roles[i] = rolePrefix + roles[i].toUpperCase();
      }

      // DB에서 url을 읽어올 때 앞에 '/'이 없다면
      // 앞에 '/'를 넣어준다.
      String url = m.get("url").toString();
      if(url.charAt(0) != '/') {
        url = "/" + url;
      }

      // url, 권한 정보를 넣는다.
      http.authorizeRequests()
      .antMatchers(url)
      .hasAnyAuthority(roles);

    }

    http.authorizeRequests()
    .antMatchers("/**").permitAll()	
    .anyRequest().authenticated();

  }

}

 

4. 테스트해서 이전 방식과 동일한 결과가 나오는지 확인합니다.

운영자(ROLE_ADMIN)로 접속한 경우

 

손님(ROLE_GUEST)로 접속한 경우

로그인하지 않고 접속하는 경우

[caption id=”attachment_1909” align=”alignnone” width=”365”] 모든 페이지 접속 시도 시 로그인 화면으로 리다이렉트됨[/caption]

 

[rcblock id=”3197”]

This post is licensed under CC BY 4.0 by the author.