maven 기반 종합 프로젝트 구축 (4) - 사용자 정의 spring security 필터

1. spring security - 사용자 정의 필터
    1. 이전 편 을 바탕 으로 spring Security Simple - config. xml 파일 을 수정 합 니 다.

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security" 
	xmlns:beans="http://www.springframework.org/schema/beans" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
		http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
		http://www.springframework.org/schema/security 
		http://www.springframework.org/schema/security/spring-security-3.0.xsd">
	<http auto-config="true" access-denied-page="/403.jsp" >
		<!--     -->
		<intercept-url pattern="/**" access="ROLE_ADMIN" />
		<intercept-url pattern="/login.jsp" filters="none"/>
		<intercept-url pattern="/loginError.do" filters="none"/>
		<intercept-url pattern="/redirectAddUser.do" filters="none"/>
		<intercept-url pattern="/common/**" filters="none"/>
		<intercept-url pattern="/styles/**" filters="none"/>
		<!--      -->
		<form-login login-page="/login.jsp" 
			always-use-default-target="true" 
			default-target-url="/securityLogin.do" 
			authentication-failure-url="/loginError.do" />
		<!--      -->
		<logout logout-success-url="/login.jsp" invalidate-session="true" />
		<!-- session   -->
		<session-management invalid-session-url="/sessionTimeout.do" 
			session-fixation-protection="migrateSession">
			<concurrency-control max-sessions="1" error-if-maximum-exceeded="true"/>
		</session-management>
		<!--                -->
		<custom-filter ref="filterSecurityInterceptor" before="FILTER_SECURITY_INTERCEPTOR"/>
		<http-basic/>
	</http>
	<!--  
		               :
			AuthenticationManager     ,        
			AccessDecisionManager:         ,           
			securityMetadataSource:       ,              
				FilterSecurityInterceptor.setSecurityMetadataSource()    FilterSecurityMetadataSource  ,
				  SecurityMetadataSource   
	-->
	<beans:bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
		<beans:property name="authenticationManager" ref="authenticationManager" />
		<beans:property name="accessDecisionManager" ref="accessDecisionManager" />
		<beans:property name="securityMetadataSource" ref="mySecurityMetadataSource" />
	</beans:bean>
	<!--      ,    ,myUserDetailService              -->
	<authentication-manager alias="authenticationManager">
		<authentication-provider user-service-ref="myUserDetailService">
			<password-encoder ref="md5Encoder">
				<salt-source user-property="username"/>
			</password-encoder>
		</authentication-provider>
	</authentication-manager>
	<!--          -->
	<beans:bean id="md5Encoder" class="com.cpkf.notpad.security.impl.MD5EncoderImpl"/>
	<!-- 
		          
		allowIfAllAbstainDecisions:               ,false-     decisionVoters  ,     
	-->
	<beans:bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
		<beans:property name="allowIfAllAbstainDecisions" value="false" />
		<beans:property name="decisionVoters">
			<beans:list>
				<beans:bean class="org.springframework.security.access.vote.RoleVoter">
					<beans:property name="rolePrefix" value="ROLE_" />
				</beans:bean>
				<beans:bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
			</beans:list>
		</beans:property>
	</beans:bean>
	<!--           -->
	<beans:bean id="mySecurityMetadataSource" class="com.cpkf.notpad.security.impl.MySecurityMetadataSource" init-method="loadResourceDefine" />
</beans:beans>

   
우선, 우 리 는 필터 가 어떻게 작 동 하 는 지 이해 해 야 한다. 그것 은 주로 다음 세 부분 에 의존한다.        AuthenticationManager 인증 관리자, 사용자 인증 입구 실현        AccessDecisionManager: 제어 정책 관리자 에 접근 하여 사용자 가 가지 고 있 는 역할 을 결정 합 니 다.        security MetadataSource: 자원 소스 데이터 정의, 특정한 자원 이 어떤 역할 에 접근 할 수 있 는 지 정의 합 니 다.    Google 이 사용 하 는 것 은 기본 필터 체인 의 org. spring from work. security. web. access. intercept. FilterSecurity Interceptor 필터 입 니 다. 다만 중요 한 인증 관리 와 자원 소스 데 이 터 를 자신의 것 으로 정의 합 니 다. AuthenticationManager 에 서 는 이전에 데 이 터 를 얻 었 던 세 가지 방식 을 사용 하지 않 습 니 다.사용자 정의 UserDetailService 로 로그 인 사용자 정 보 를 얻 고 인증 관리자 에 게 값 을 부여 합 니 다. security MetadataSource 에서 저 희 는 url 자원 라 이브 러 리 의 모든 url 과 일치 하 는 역할 을 초기 화 한 다음 에 모든 url 요청 과 초기 화 데 이 터 를 비교 하여 권한 수여 여 부 를 판단 합 니 다.
    2、MyUserDetailServiceImpl
    인터페이스 MyUserDetailService 를 뽑 았 습 니 다. 인터페이스 계승 org. springframework. security. core. userdetails. UserDetailsService

package com.cpkf.notpad.security.impl;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import com.cpkf.notpad.entity.Account;
import com.cpkf.notpad.entity.Resource;
import com.cpkf.notpad.entity.Role;
import com.cpkf.notpad.security.MyUserDetailService;
import com.cpkf.notpad.server.IAccountService;
/**  
 * Filename:    MyUserDetailServiceImpl.java
 * Description:      UserDetailService        ,         
 * Company:     
 * @author:     Jiang.hu
 * @version:    1.0
 * Create at:   May 26, 2011 4:23:27 PM
 * modified:    
 */
@Service("myUserDetailService")
public class MyUserDetailServiceImpl implements MyUserDetailService {
	private static final Logger logger = Logger.getLogger(MyUserDetailServiceImpl.class);
	@Autowired
	private IAccountService accountService;
	public UserDetails loadUserByUsername(String username) 
		throws UsernameNotFoundException, DataAccessException {
		//    
		Account account = accountService.getAccountByEmail(username);
		if(account == null){
			logger.info("Can not found any Account by given username:" + username);
			throw new UsernameNotFoundException("Can not found any Account by given username:" + username);
		}
		//      
		Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
		if(!account.getRoles().isEmpty() && account.getRoles() != null){
			Iterator<Role> roleIterator = account.getRoles().iterator();
			while(roleIterator.hasNext()){
				Role role = roleIterator.next();
				GrantedAuthority grantedAuthority = new GrantedAuthorityImpl(role.getRoleName().toUpperCase());
				System.out.println("    :" + role.getRoleName().toUpperCase());
				authorities.add(grantedAuthority);
			}
		}
		
		return new User(username, account.getPassWord(), true, true, true, true, authorities);
	}

}

    3、MySecurityMetadataSource

package com.cpkf.notpad.security.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.AntUrlPathMatcher;
import org.springframework.security.web.util.UrlMatcher;
import com.cpkf.notpad.entity.Resource;
import com.cpkf.notpad.entity.Role;
import com.cpkf.notpad.server.IResourceService;
/**  
 * Filename:    MySecurityMetadataSource.java
 * Description:        ,              
 * Company:     
 * @author:     Jiang.hu
 * @version:    1.0
 * Create at:   May 26, 2011 5:04:50 PM
 * modified:    
 */
public class MySecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
	private static final Logger logger = Logger.getLogger(MySecurityMetadataSource.class);
	@Autowired
	private IResourceService resourceService;
	private static Map<String, Collection<ConfigAttribute>> resourceMap = null;
	private UrlMatcher urlMatcher;
	public MySecurityMetadataSource(){
		urlMatcher = new AntUrlPathMatcher();
		resourceMap = new HashMap<String, Collection<ConfigAttribute>>();
		//              ,               
//		loadResourceDefine();
	}
	/* 
	 * method name   : loadResourceDefine
	 * description   :      ,                 
	 * @author       : Jiang.Hu
	 * @param        : 
	 * @return       : void
	 * Create at     : May 27, 2011 2:38:26 PM
	 * modified      : 
	 */      
	public void loadResourceDefine(){
		List<Resource> resources = resourceService.getAllResources();
		if(resources != null && !resources.isEmpty()){
			for(Resource resource : resources){
				Collection<ConfigAttribute> configAttributes = new ArrayList<ConfigAttribute>();
				Iterator<Role> roleIterator = resource.getRoles().iterator();
				while(roleIterator.hasNext()){
					Role role = roleIterator.next();
					ConfigAttribute configAttribute = new SecurityConfig(role.getRoleName());
					configAttributes.add(configAttribute);
				}
				resourceMap.put(resource.getUrl(), configAttributes);
			}
		}
	}
	/* 
	 * method name   : getAttributes
	 * description   :    url      ,                   url
	 * @author       : Jiang.Hu
	 * modified      : leo ,  May 27, 2011
	 * @see          : @see org.springframework.security.access.SecurityMetadataSource#getAttributes(java.lang.Object)
	 */    
	public Collection<ConfigAttribute> getAttributes(Object object) 
		throws IllegalArgumentException {
		if((object == null) || !this.supports(object.getClass())){
			logger.info("Object must be a FilterInvocation");
			throw new IllegalArgumentException("Object must be a FilterInvocation");
		}
		Collection<ConfigAttribute> configAttributes = new ArrayList<ConfigAttribute>();
		if(object instanceof FilterInvocation){
			String requestUrl = ((FilterInvocation)object).getRequestUrl();
			System.out.println("  url:" + requestUrl);
			//    url    url,            
			if(resourceMap != null && !resourceMap.isEmpty()){
				Iterator<String> iterator = resourceMap.keySet().iterator();
				while(iterator.hasNext()){
					String resourceUrl = iterator.next();
					if(urlMatcher.pathMatchesUrl(resourceUrl, requestUrl)){
						configAttributes.addAll(resourceMap.get(resourceUrl));
					}
				}
				if(configAttributes.isEmpty()){
					configAttributes.add(new SecurityConfig("nobody"));
				}
				for(ConfigAttribute configAttribute : configAttributes){
					System.out.println("  url    :" + configAttribute.toString());
				}
				return configAttributes;
			}
		}
		return null;
	}

	public Collection<ConfigAttribute> getAllConfigAttributes() {
		return new ArrayList<ConfigAttribute>();
	}

	public boolean supports(Class<?> clazz) {
		return FilterInvocation.class.isAssignableFrom(clazz);
	}
}

    4. 이렇게 우리 는[email protected]예 를 들 어 사용자 역할 과 자원 바 인 딩 효 과 를 실현 합 니 다.
    [email protected]사용자 보유 ROLEADMIN 역할, 로그 인 하여 "/ security Login. do" url 에 접근 할 때 resource 자원 라 이브 러 리 에 "/ security Login. do" 가 ROLE 없 으 면ADMIN 캐릭터, 이 사용 자 는 권한 이 없습니다. 403 페이지 로 넘 어가 야 합 니 다.
        사용자 역할: ROLEADMIN
        사용자 역할: ROLEGUEST
        요청 url: / security Login. do
        요청 url 일치 캐릭터: nobody
    리 소스 자원 라 이브 러 리 에 "/ security Login. do" 가 ROLE 가 있다 면ADMIN 역할, 이 사용자 만 접근 가능
        사용자 역할: ROLEADMIN
        사용자 역할: ROLEGUEST
        요청 url: / security Login. do
        요청 url 매 칭 캐릭터: ROLEADMIN
    5. 위의 기초 가 있 으 면 사용자 권한 관 리 를 설계 합 니 다.
        우선 사용자 가 없 는 상태 에서 접근 할 url 입 니 다. 필터 검증 이 필요 없습니다.

<intercept-url pattern="/**" access="ROLE_ADMIN" />
		<intercept-url pattern="/login.jsp" filters="none"/>
		<intercept-url pattern="/redirectAddUser.do" filters="none"/>
		<intercept-url pattern="/redirectRegist.do" filters="none"/>
		<intercept-url pattern="/loginError.do" filters="none"/>
		<intercept-url pattern="/sessionTimeout.do" filters="none"/>
		<intercept-url pattern="/visualCode.do" filters="none"/>
		<intercept-url pattern="/addAccount.do" filters="none"/>
		<intercept-url pattern="/styles/**" filters="none"/>
		<intercept-url pattern="/scripts/**" filters="none"/>
		<intercept-url pattern="/images/**" filters="none"/>

        그 다음 에 공공 url 자원 을 디자인 하고 모든 역할 에 부여 한다.

package com.cpkf.notpad.commons.constants;

/**  
 * Filename:    PublicResourceEnum.java
 * Description:     
 * 				home-        (/*          ,/**        )
 * 				owner-owner     ,      eg       
 * Company:     
 * @author:     Jiang.hu
 * @version:    1.0
 * Create at:   May 30, 2011 10:53:27 AM
 * modified:    
 */
public enum PublicResourceEnum {
	OWNER("owner","/owner/**"),HOME("home","/*");
	private String publicResourceName;
	private String publicResourcePath;
	private PublicResourceEnum(String publicResourceName, String publicResourcePath) {
		this.publicResourceName = publicResourceName;
		this.publicResourcePath = publicResourcePath;
	}
	public String getPublicResourceName() {
		return publicResourceName;
	}
	public String getPublicResourcePath() {
		return publicResourcePath;
	}
	
}

        MySecurity MetadataSource 클래스 에 loadPublicResources 방법 을 추가 하고 초기 화 방법 loadResourceDefine 에서 호출 합 니 다.

public void loadPublicResources(){
		List<Role> roles = roleService.getAllRoles();
		for(PublicResourceEnum publicResourceEnum : PublicResourceEnum.values()){
			Collection<ConfigAttribute> configAttributes = new ArrayList<ConfigAttribute>();
			for(Role role : roles){
				ConfigAttribute configAttribute = new SecurityConfig(role.getRoleName());
				configAttributes.add(configAttribute);
			}
			resourceMap.put(publicResourceEnum.getPublicResourcePath(), configAttributes);
		}
	}

        이렇게 되면 모든 가입 자 는 / * 1 급 자원 과 '/ owner / * 2 급 주소 에서 모든 자원 을 방문 할 수 있 고 다른 2 급 자원 은 resource 표 에서 지정 하여 해당 하 는 role 에 할당 할 수 있 습 니 다.

좋은 웹페이지 즐겨찾기