Spring Security 에서 어떻게 상급자 가 하급 자의 모든 권한 을 가지 게 합 니까(사례 분석)

12564 단어 SpringSecurity권한
정 답 은 할 수 있어!
송 형 은 전에 비슷 한 글 을 쓴 적 이 있 지만 주로 용법 을 말 했 습 니 다.오늘 은 원 리 를 봅 시다!
본 고 는 현재 Spring Security 5.3.4 를 바탕 으로 분석 하 는데 왜 최신 판 을 강조 합 니까?5.0.11 버 전에 서 는 캐릭터 계승 구성 이 지금 과 다 르 기 때문이다.구 판 의 방안 을 우 리 는 지금 토론 하지 않 고 현재 최신 판 이 어떻게 처리 되 는 지 직접 보 자.
1.캐릭터 계승 사례
우 리 는 먼저 간단 한 권한 사례 를 하나 하 자.
Spring Boot 프로젝트 를 만 들 고 Spring Security 의존 도 를 추가 하 며 두 개의 테스트 사용 자 를 만 듭 니 다.다음 과 같 습 니 다.

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
 auth.inMemoryAuthentication()
  .withUser("javaboy")
  .password("{noop}123").roles("admin")
  .and()
  .withUser("     ")
  .password("{noop}123")
  .roles("user");
}
그리고 세 개의 테스트 인 터 페 이 스 를 준비 합 니 다.다음 과 같 습 니 다.

@RestController
public class HelloController {
 @GetMapping("/hello")
 public String hello() {
 return "hello";
 }

 @GetMapping("/admin/hello")
 public String admin() {
 return "admin";
 }

 @GetMapping("/user/hello")
 public String user() {
 return "user";
 }
}
이 세 개의 테스트 인터페이스,우리 의 계획 은 다음 과 같다.
  • /hello 는 누구나 접근 할 수 있 는 인터페이스
  • /admin/hello 는 admin 신분 을 가 진 사람 만 접근 할 수 있 는 인터페이스
  • /user/hello 는 user 신분 을 가 진 사람 만 접근 할 수 있 는 인터페이스
  • 모든 user 가 접근 할 수 있 는 자원,admin 이 접근 할 수 있 습 니 다
  • 제4 조 규범 에 주의 하 는 것 은 admin 신분 을 가 진 모든 사람 이 자동 으로 user 신분 을 갖 추 는 것 을 의미한다.
    다음 권한 의 차단 규칙 을 설정 합 니 다.Spring Security 의 configure(HttpSecurity http)방법 에서 코드 는 다음 과 같 습 니 다.
    
    http.authorizeRequests()
     .antMatchers("/admin/**").hasRole("admin")
     .antMatchers("/user/**").hasRole("user")
     .anyRequest().authenticated()
     .and()
     ...
     ...
    여기 서 일치 하 는 규칙 은 Ant 스타일 의 경로 일치 부 호 를 사 용 했 습 니 다.Ant 스타일 의 경로 일치 부 호 는 Spring 가족 에서 매우 광범 위 하 게 사용 되 고 일치 하 는 규칙 도 매우 간단 합 니 다.
    어댑터
    속뜻
    **
    일치 하 는 다 중 경로
    *
    일치 하 는 경로
    ?
    임의의 단일 문자 일치
    위 설정 의 의 미 는:
  • 요청 경로 만족/admin/**형식 이 있 으 면 사용 자 는 admin 역할 을 해 야 합 니 다.
  • 요청 경로 만족/user/**형식 이 있 으 면 사용 자 는 user 역할 을 가 져 야 합 니 다.
  • 남 은 다른 형식의 요청 경 로 는 인증(로그 인)만 하면 접근 할 수 있 습 니 다.
  • 코드 에 설 정 된 세 가지 규칙 의 순 서 는 매우 중요 합 니 다.Shiro 와 유사 합 니 다.Spring Security 는 일치 할 때 도 위 에서 아래로 순서대로 일치 합 니 다.일치 하면 계속 일치 하지 않 기 때문에 차단 규칙 의 순 서 를 잘못 쓸 수 없습니다.
    캐릭터 계승 을 사용 하면 이 기능 이 잘 실 현 됩 니 다.저 희 는 Security Config 에 다음 과 같은 코드 를 추가 하여 캐릭터 계승 관 계 를 설정 하면 됩 니 다.
    
    @Bean
    RoleHierarchy roleHierarchy() {
     RoleHierarchyImpl hierarchy = new RoleHierarchyImpl();
     hierarchy.setHierarchy("ROLE_admin > ROLE_user");
     return hierarchy;
    }
    설정 할 때 캐릭터 에 수 동 으로 접 두 사 를 붙 여야 합 니 다ROLE_.위의 설정 은ROLE_admin자동 으로ROLE_user권한 을 갖 추고 있 음 을 나타 낸다.
    다음 에 우 리 는 프로젝트 를 시작 하여 테스트 를 진행한다.
    프로젝트 시작 에 성공 한 후,우 리 는 먼저 강남 약간의 비 로 로그 인 합 니 다.

    로그 인 성공 후 각각/hello,/admin/hello/user/hello세 개의 인 터 페 이 스 를 방문 합 니 다.그 중에서:
  • /hello로그 인 하면 접근 할 수 있 기 때문에 이 인터페이스 에 성공 했다.
  • /admin/helloadmin 신분 이 필요 해서 방문 에 실 패 했 습 니 다.
  • /user/hellouser 신분 이 필요 해서 방문 에 성 공 했 습 니 다.
  • 자바 보이 로 로그 인 합 니 다.로그 인 에 성공 한 후에 자바 보이 도/user/hello인 터 페 이 스 를 방문 할 수 있 습 니 다.이것 은 우리 의 캐릭터 계승 설정 에 문제 가 없다 는 것 을 설명 합 니 다!
    2.원리 분석
    이 설정 의 핵심 은 우리 가 Role Hierarchy 인 스 턴 스 를 제공 하 는 것 입 니 다.그래서 우리 의 분석 은 이런 종류 에서 시작 합 니 다.
    Role Hierarchy 는 인터페이스 입 니 다.이 인터페이스 에는 방법 이 하나 밖 에 없습니다.
    
    public interface RoleHierarchy {
    	Collection<? extends GrantedAuthority> getReachableGrantedAuthorities(
    			Collection<? extends GrantedAuthority> authorities);
    
    }
    이 방법 은 authorities 권한 집합 입 니 다.방법 명 으로 볼 때 방법의 반환 값 은 접근 가능 한 권한 집합 입 니 다.
    간단 한 예 를 들 어 캐릭터 차원 구 조 는ROLE_A > ROLE_B > ROLE_C이 라 고 가정 하고 현재 사용자 에 게 직접 분배 하 는 권한 은ROLE_A이지 만 실제 사용자 가 가 진 권한 은ROLE_A,ROLE_BROLE_C가 있다.
    getReachable Granted Authorities 방법의 목적 은 캐릭터 차원 에 따라 사용자 가 진정 으로 도달 할 수 있 는 캐릭터 를 분석 하 는 것 이다.
    Role Hierarchy 인 터 페 이 스 는 두 가지 실현 유형 이 있 는데 다음 과 같다.
  • NullRole Hierarchy 는 들 어 오 는 인 자 를 그대로 되 돌려 주 는 빈 구현 입 니 다.
  • Role Hierarchy Impl 은 우리 가 앞에서 사용 한 실현 입 니 다.이것 은 해석 작업 을 완성 할 것 입 니 다.
  • Role Hierarchy Impl 류 를 중점적으로 살 펴 보 겠 습 니 다.
    이 유형 에서 실제 적 으로 네 가지 방법setHierarchy,getReachableGrantedAuthorities,buildRolesReachableInOneStepMapbuildRolesReachableInOneOrMoreStepsMap에 대해 우 리 는 하나씩 분석 했다.
    먼저 우리 가 처음에 호출 한 setHierarchy 방법 입 니 다.이 방법 은 캐릭터 의 등급 관 계 를 설정 하 는 데 사 용 됩 니 다.
    
    public void setHierarchy(String roleHierarchyStringRepresentation) {
    	this.roleHierarchyStringRepresentation = roleHierarchyStringRepresentation;
    	if (logger.isDebugEnabled()) {
    		logger.debug("setHierarchy() - The following role hierarchy was set: "
    				+ roleHierarchyStringRepresentation);
    	}
    	buildRolesReachableInOneStepMap();
    	buildRolesReachableInOneOrMoreStepsMap();
    }
    사용자 가 들 어 오 는 문자열 변 수 는 role Hierarchy String Representation 속성 에 설정 한 다음 buildRolesReachable InOne StepMap 과 buildRolesReachable InOne Ore StepsMap 방법 을 통 해 캐릭터 등급 에 대한 분석 을 완성 합 니 다.
    buildRolesReachable InOne StepMap 방법 은 캐릭터 관 계 를 한 층 한 층 의 형식 으로 해석 하 는 데 사용 된다.우 리 는 그것 의 소스 코드 를 살 펴 보 자.
    
    private void buildRolesReachableInOneStepMap() {
    	this.rolesReachableInOneStepMap = new HashMap<>();
    	for (String line : this.roleHierarchyStringRepresentation.split("
    ")) { String[] roles = line.trim().split("\\s+>\\s+"); for (int i = 1; i < roles.length; i++) { String higherRole = roles[i - 1]; GrantedAuthority lowerRole = new SimpleGrantedAuthority(roles[i]); Set<GrantedAuthority> rolesReachableInOneStepSet; if (!this.rolesReachableInOneStepMap.containsKey(higherRole)) { rolesReachableInOneStepSet = new HashSet<>(); this.rolesReachableInOneStepMap.put(higherRole, rolesReachableInOneStepSet); } else { rolesReachableInOneStepSet = this.rolesReachableInOneStepMap.get(higherRole); } rolesReachableInOneStepSet.add(lowerRole); } } }
    먼저,줄 바 꿈 문자 에 따라 사용자 가 설정 한 여러 캐릭터 의 등급 을 분석 하 는 것 을 보 았 습 니 다.이것 은 무슨 뜻 입 니까?
    우리 앞의 사례 에서 설정 만 했 습 니 다ROLE_admin > ROLE_user.만약 에 여러 개의 계승 관 계 를 설정 해 야 한다 면 어떻게 설정 합 니까?여러 개의 상속 관 계 를
    로 분리 하면 다음 과 같다ROLE_A > ROLE_B
    ROLE_C > ROLE_D
    .캐릭터 의 등급 관계 가 연속 적 이면 이렇게 배치 할 수 있 는 경우 도 있다ROLE_A > ROLE_B > ROLE_C > ROLE_D.
    그래서 여 기 는 먼저
    로 다 층 상속 관 계 를 분리 하여 하나의 배열 을 만 든 다음 에 배열 을 옮 겨 다 닌 다.
    구체 적 으로 옮 겨 다 니 면서>캐릭터 관 계 를 하나의 배열 로 나 눈 다음 에 배열 을 분석 하고 높 은 등급 의 캐릭터 를 key 로 하고 낮은 등급 의 캐릭터 를 value 로 한다.
    코드 가 비교적 간단 합 니 다.마지막 으로 rolesReachable InOne StepMap 에 저 장 된 등급 관 계 는 다음 과 같 습 니 다.
    캐릭터 계승 관 계 를 가정 하면ROLE_A > ROLE_B
    ROLE_C > ROLE_D
    ROLE_C > ROLE_E
    맵 의 데 이 터 는 다음 과 같다.
  • AC>B
  • CC>[D,E]
  • 캐릭터 계승 관 계 를 가정 하면ROLE_A > ROLE_B > ROLE_C > ROLE_D맵 의 데 이 터 는 다음 과 같다.
  • AC>B
  • BC>C
  • CC>D
  • buildRolesReachable InOne StepMap 방법 으로 분 석 된 rolesReachable InOne StepMap 집합 입 니 다.
    다음 buildRolesReachable InOne Ore StepsMap 방법 은 rolesReachable InOne StepMap 집합 을 재해 석 하여 캐릭터 의 계승 관 계 를 평평 하 게 하 는 것 이다.
    예 를 들 어 rolesReachable InOne StepMap 에 저 장 된 캐릭터 계승 관 계 는 다음 과 같다.
  • AC>B
  • BC>C
  • CC>D
  • buildRolesReachable InOneOre StepsMap 방법 을 분석 한 후 새로운 Map 에 저 장 된 데 이 터 는 다음 과 같 습 니 다.
  • AC>[B、C、D]
  • BC>[C、D]
  • CC>D
  • 이렇게 해석 이 끝나 면 모든 캐릭터 가 닿 을 수 있 는 캐릭터 를 한눈 에 알 수 있다.
    buildRolesReachable InOneOre StepsMap 방법의 실현 논 리 를 살 펴 보 겠 습 니 다.
    
    private void buildRolesReachableInOneOrMoreStepsMap() {
    	this.rolesReachableInOneOrMoreStepsMap = new HashMap<>();
    	for (String roleName : this.rolesReachableInOneStepMap.keySet()) {
    		Set<GrantedAuthority> rolesToVisitSet = new HashSet<>(this.rolesReachableInOneStepMap.get(roleName));
    		Set<GrantedAuthority> visitedRolesSet = new HashSet<>();
    		while (!rolesToVisitSet.isEmpty()) {
    			GrantedAuthority lowerRole = rolesToVisitSet.iterator().next();
    			rolesToVisitSet.remove(lowerRole);
    			if (!visitedRolesSet.add(lowerRole) ||
    					!this.rolesReachableInOneStepMap.containsKey(lowerRole.getAuthority())) {
    				continue;
    			} else if (roleName.equals(lowerRole.getAuthority())) {
    				throw new CycleInRoleHierarchyException();
    			}
    			rolesToVisitSet.addAll(this.rolesReachableInOneStepMap.get(lowerRole.getAuthority()));
    		}
    		this.rolesReachableInOneOrMoreStepsMap.put(roleName, visitedRolesSet);
    	}
    }
    이 방법 은 비교적 교묘 하 다.우선 roleName 에 따라 rolesReachable InOne StepMap 에서 대응 하 는 rolesToVisitSet 를 가 져 옵 니 다.이 rolesToVisitSet 은 Set 집합 으로 옮 겨 다 니 며,옮 겨 다 니 는 결 과 를 visited RolesSet 집합 에 추가 합 니 다.rolesReachable InOne StepMap 집합 키 가 이전에 읽 은 lowerRole 을 포함 하지 않 으 면,이 lowerRole 이 전체 캐릭터 시스템 의 최 하층 이 고 직접 continue 라 는 뜻 이다.그렇지 않 으 면 lowerRole 을 rolesReachable InOne StepMap 에 대응 하 는 value 를 꺼 내 서 계속 옮 겨 다 니 세 요.
    마지막 으로 스 트 리밍 결 과 를 rolesReachable InOne OrMore StepsMap 집합 에 저장 하면 됩 니 다.
    이 방법 은 좀 복잡 하 니,젊은이 들 은 스스로 단점 을 만들어 볼 수 있다.
    위의 분석 을 보면 젊은이 들 이 발 견 했 을 수도 있 지만 사실은 캐릭터 계승 은 결국 비 겼 다.
    우리 가 정의 한 역할 은 등급 이 있 지만 코드 에서 이런 등급 을 평평 하 게 해서 후속 적 인 비교 에 편리 하 다.
    마지막 으로 getReachable Granted Authorities 방법 도 있 습 니 다.들 어 오 는 캐릭터 에 따라 잠재 적 으로 포 함 될 수 있 는 캐릭터 를 분석 합 니 다.
    
    public Collection<GrantedAuthority> getReachableGrantedAuthorities(
    		Collection<? extends GrantedAuthority> authorities) {
    	if (authorities == null || authorities.isEmpty()) {
    		return AuthorityUtils.NO_AUTHORITIES;
    	}
    	Set<GrantedAuthority> reachableRoles = new HashSet<>();
    	Set<String> processedNames = new HashSet<>();
    	for (GrantedAuthority authority : authorities) {
    		if (authority.getAuthority() == null) {
    			reachableRoles.add(authority);
    			continue;
    		}
    		if (!processedNames.add(authority.getAuthority())) {
    			continue;
    		}
    		reachableRoles.add(authority);
    		Set<GrantedAuthority> lowerRoles = this.rolesReachableInOneOrMoreStepsMap.get(authority.getAuthority());
    		if (lowerRoles == null) {
    			continue;
    		}
    		for (GrantedAuthority role : lowerRoles) {
    			if (processedNames.add(role.getAuthority())) {
    				reachableRoles.add(role);
    			}
    		}
    	}
    	List<GrantedAuthority> reachableRoleList = new ArrayList<>(reachableRoles.size());
    	reachableRoleList.addAll(reachableRoles);
    	return reachableRoleList;
    }
    이 방법의 논 리 는 비교적 직 설 적 이다.바로 rolesReachable InOne OrMore StepsMap 집합 에서 현재 캐릭터 가 진정 으로 방문 할 수 있 는 캐릭터 정 보 를 조회 하 는 것 이다.
    3.RoleHierarchyVoter
    getReachable Granted Authorities 방법 은 Role Hierarchy Voter 투표 기 에서 호출 됩 니 다.
    
    public class RoleHierarchyVoter extends RoleVoter {
    	private RoleHierarchy roleHierarchy = null;
    	public RoleHierarchyVoter(RoleHierarchy roleHierarchy) {
    		Assert.notNull(roleHierarchy, "RoleHierarchy must not be null");
    		this.roleHierarchy = roleHierarchy;
    	}
    	@Override
    	Collection<? extends GrantedAuthority> extractAuthorities(
    			Authentication authentication) {
    		return roleHierarchy.getReachableGrantedAuthorities(authentication
    				.getAuthorities());
    	}
    }
    Spring Security 투표 기 에 대해 서 는 또 다른 이야기 가 될 것 입 니 다.송 형 은 다음 글 에서 어린이 들 과 투표 기와 의사 결정 기 를 공유 할 것 입 니 다~
    4.소결
    스프링 시 큐 리 티 에서 상급자 가 하급 자 에 게 어떻게 모든 권한 을 가 질 수 있 는 지 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 관련 스프링 시 큐 리 티 상급자 가 하급 자 에 게 모든 권한 을 가 진 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 도 많은 지원 을 바 랍 니 다!

    좋은 웹페이지 즐겨찾기