사용자 정의 Spring Security 권한 제어 관리 (실전 편)

전편 'Spring Security 권한 관리 (소스 코드)' 는 Spring Security 권한 제어 관리의 소스 코드 와 실현 을 소개 했다. 그러나 어떤 경우 에는 기본 적 인 실현 이 우리 프로젝트 의 실제 수 요 를 만족 시 키 지 못 하고 가끔 은 자신의 실현 이 필요 하 다. 이번 에는 지난번 내용 을 중심 으로 프로젝트 실전 을 할 것 이다.
실전 배경
배경 설명
프로젝트 에 서 는 url + httpmethod (restful 만족, 예 를 들 어:https://.../xxx/users/1일부 캐릭터 는 (HTTP GET) 만 볼 수 있 고, 추가 삭제 (POST, PUT, DELETE) 할 권리 가 없습니다.
시계 설계
혐의 를 피하 기 위해 서 는 사용 할 관건 적 인 필드 만 열거 하고, 나머지 는 스스로 머리 를 써 서 보충 하 시기 바 랍 니 다.
  • admin_user 관리자 사용자 테이블, 키 필드 (id, role id).
  • t_role 역할 표, 키 필드 (id, privilege id).
  • t_privilege 권한 표, 키 필드 (id, url, method)
  • 세 표 의 관련 관 계 는 더 이상 말 할 필요 가 없 겠 지, 필드 를 보면 한눈 에 알 수 있다.
    실현 전 분석
    우 리 는 역방향 으로 생각 할 수 있다.
    우리 의 수 요 를 실현 하려 면 가장 중요 한 단 계 는 Spring Security 의 AccessDecisionManager 로 하여 금 요청 한 url + httpmethod 가 우리 데이터베이스 의 설정 에 부합 되 는 지 판단 하 게 하 는 것 입 니 다.그러나 AccessDecisionManager 는 유사 한 수요 와 관련 된 Voter 를 판정 하지 않 았 기 때문에 우 리 는 Voter 의 실현 을 사용자 정의 해 야 한다 (기본적으로 등 록 된 Affirmative Based 의 전략 은 Voter 가 ACCESS GRANTED 표를 던 지면 통과 로 판정 하 는 것 도 우리 의 요구 에 부합 한다).voter 를 실현 한 후 중요 한 매개 변수 (Collection attributes) 가 있 습 니 다. ConfigAttribute 는 상황 에 따라 의미 가 다 릅 니 다.우 리 는 여기 서도 이 루어 져 야 한다.그러나 Collection attributes 인 자 는 Security MetadataSource 에서 얻 을 수 있 기 때문에 우 리 는 Security MetadataSource 를 실현 해 야 합 니 다.Spring Security 에서 현재 사용자 인증 정 보 는 Authentication 을 통 해 표 시 된 것 으로 알려 져 있 으 므 로 Authentication 에 사용자 (admin) 인 스 턴 스 를 포함 시 켜 야 합 니 다.Authentication 은 사용자 의 권한 정보 (Granted Authority) 도 포함 하고 있 기 때문에 Granted Authority 도 실현 해 야 합 니 다.
    사고의 절 차 를 정리 하 다.
    1. 사용자 정의 voter 구현.
    2. 사용자 정의 ConfigAttribute 구현.
    3. 사용자 정의 Security MetadataSource 구현.
    4. Authentication 은 사용자 인 스 턴 스 를 포함 합 니 다.
    5. 사용자 정의 Granted Authority 구현.
    프로젝트 실전
    1. 사용자 정의 GrantedAuthority 구현
    UrlGrantedAuthority.java
    public class UrlGrantedAuthority implements GrantedAuthority {
    
        private final String httpMethod;
    
        private final String url;
    
        public UrlGrantedAuthority(String httpMethod, String url) {
            this.httpMethod = httpMethod;
            this.url = url;
        }
    
        @Override
        public String getAuthority() {
            return url;
        }
    
        public String getHttpMethod() {
            return httpMethod;
        }
    
        public String getUrl() {
            return url;
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
    
            UrlGrantedAuthority target = (UrlGrantedAuthority) o;
            if (httpMethod.equals(target.getHttpMethod()) && url.equals(target.getUrl())) return true;
            return false;
        }
    
        @Override
        public int hashCode() {
            int result = httpMethod != null ? httpMethod.hashCode() : 0;
            result = 31 * result + (url != null ? url.hashCode() : 0);
            return result;
        }
    }

    2. 사용자 정의 인증 사용자 인 스 턴 스
    public class SystemUser implements UserDetails {
    
        private final Admin admin;
    
        private List menuOutputList;
    
        private final List grantedAuthorities;
    
        public SystemUser(Admin admin, List grantedPrivileges, List menuOutputList) {
            this.admin = admin;
            this.grantedAuthorities = grantedPrivileges.stream().map(it -> {
                String method = it.getMethod() != null ? it.getMethod().getLabel() : null;
                return new UrlGrantedAuthority(method, it.getUrl());
            }).collect(Collectors.toList());
            this.menuOutputList = menuOutputList;
        }
    
        @Override
        public Collection extends GrantedAuthority> getAuthorities() {
            return this.grantedAuthorities;
        }
    
        @Override
        public String getPassword() {
            return admin.getPassword();
        }
    
        @Override
        public String getUsername() {
            return null;
        }
    
        @Override
        public boolean isAccountNonExpired() {
            return true;
        }
    
        @Override
        public boolean isAccountNonLocked() {
            return true;
        }
    
        @Override
        public boolean isCredentialsNonExpired() {
            return true;
        }
    
        @Override
        public boolean isEnabled() {
            return true;
        }
    
        public Long getId() {
            return admin.getId();
        }
    
        public Admin getAdmin() {
            return admin;
        }
    
        public List getMenuOutputList() {
            return menuOutputList;
        }
    
        public String getSalt() {
            return admin.getSalt();
        }
    }   

    3. 사용자 정의 UrlConfigAttribute 구현
    public class UrlConfigAttribute implements ConfigAttribute {
    
        private final HttpServletRequest httpServletRequest;
    
        public UrlConfigAttribute(HttpServletRequest httpServletRequest) {
            this.httpServletRequest = httpServletRequest;
        }
    
    
        @Override
        public String getAttribute() {
            return null;
        }
    
        public HttpServletRequest getHttpServletRequest() {
            return httpServletRequest;
        }
    }

    4. 사용자 정의 Security MetadataSource 구현
    public class UrlFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
    
        @Override
        public Collection getAttributes(Object object) throws IllegalArgumentException {
            final HttpServletRequest request = ((FilterInvocation) object).getRequest();
            Set allAttributes = new HashSet<>();
            ConfigAttribute configAttribute = new UrlConfigAttribute(request);
            allAttributes.add(configAttribute);
            return allAttributes;
        }
    
        @Override
        public Collection getAllConfigAttributes() {
            return null;
        }
    
        @Override
        public boolean supports(Class> clazz) {
            return FilterInvocation.class.isAssignableFrom(clazz);
        }
    
    }

    5. 사용자 정의 voter 구현
    public class UrlMatchVoter implements AccessDecisionVoter {
    
        @Override
        public boolean supports(ConfigAttribute attribute) {
            if (attribute instanceof UrlConfigAttribute) return true;
            return false;
        }
    
        @Override
        public boolean supports(Class> clazz) {
            return true;
        }
    
        @Override
        public int vote(Authentication authentication, Object object, Collection attributes) {
            if(authentication == null) {
                return ACCESS_DENIED;
            }
            Collection extends GrantedAuthority> authorities = authentication.getAuthorities();
    
            for (ConfigAttribute attribute : attributes) {
                if (!(attribute instanceof UrlConfigAttribute)) continue;
                UrlConfigAttribute urlConfigAttribute = (UrlConfigAttribute) attribute;
                for (GrantedAuthority authority : authorities) {
                    if (!(authority instanceof UrlGrantedAuthority)) continue;
                    UrlGrantedAuthority urlGrantedAuthority = (UrlGrantedAuthority) authority;
                    if (StringUtils.isBlank(urlGrantedAuthority.getAuthority())) continue;
                    //      method   null,           
                    String httpMethod = StringUtils.isNotBlank(urlGrantedAuthority.getHttpMethod()) ? urlGrantedAuthority.getHttpMethod()
                            : urlConfigAttribute.getHttpServletRequest().getMethod();
                    // Spring     AntPathRequestMatcher    ,         url    ant      (  :/xxx/user/**)        
                    AntPathRequestMatcher antPathRequestMatcher = new AntPathRequestMatcher(urlGrantedAuthority.getAuthority(), httpMethod);
                    if (antPathRequestMatcher.matches(urlConfigAttribute.getHttpServletRequest()))
                        return ACCESS_GRANTED;
                }
            }
            return ACCESS_ABSTAIN;
        }
    }

    6. 사용자 정의 FilterSecurity Interceptor 구현
    public class UrlFilterSecurityInterceptor extends FilterSecurityInterceptor {
    
        public UrlFilterSecurityInterceptor() {
            super();
        }
    
        @Override
        public void init(FilterConfig arg0) throws ServletException {
            super.init(arg0);
        }
    
        @Override
        public void destroy() {
            super.destroy();
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            super.doFilter(request, response, chain);
        }
    
        @Override
        public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
            return super.getSecurityMetadataSource();
        }
    
        @Override
        public SecurityMetadataSource obtainSecurityMetadataSource() {
            return super.obtainSecurityMetadataSource();
        }
    
        @Override
        public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource newSource) {
            super.setSecurityMetadataSource(newSource);
        }
    
        @Override
        public Class> getSecureObjectClass() {
            return super.getSecureObjectClass();
        }
    
        @Override
        public void invoke(FilterInvocation fi) throws IOException, ServletException {
            super.invoke(fi);
        }
    
        @Override
        public boolean isObserveOncePerRequest() {
            return super.isObserveOncePerRequest();
        }
    
        @Override
        public void setObserveOncePerRequest(boolean observeOncePerRequest) {
            super.setObserveOncePerRequest(observeOncePerRequest);
        }
    }

    프로필 키 설정
    
        ...
        
    
    
    
        
    
    
    
        
            
                
                
                
            
        
    
    
    
    
    
        
        
        
     

    자, 이제 스프링 시 큐 리 티 권한 통제 여행 을 즐겨 보 세 요.
    제 개인 블 로그 에 오신 것 을 환영 합 니 다:
    www.javafan.cn

    좋은 웹페이지 즐겨찾기