spring security3教程系列--自定义权限管理

46 篇文章 0 订阅
26 篇文章 0 订阅

本文章摘编、转载需要注明来源 http://write.blog.csdn.net/postedit/8575062


spring security3中的权限管理虽然有文件可配置,但是很多时候我们是需要数据库的支持,下面我演示下如何配置自定义权限管理,这个时候需要重新实现下面的类,

该文章适合对spring security3 有一定理解的人员


AccessDecisionManager是验证资源跟角色之间的关系,由于我个人不太喜欢用标签化,因为感觉灵活性不够好,所以我统一是用bean方式,至于用bean来描述是需要对security的

过滤链流程和各个属性依赖关系比较熟悉的了解才可以配置成功,这样灵活性大大加强

/**
 * 
 * @author shadow
 * @email 124010356@qq.com
 * @create 2012.04.28
 */

public class AccessDecisionManagerImpl implements AccessDecisionManager {

	public void decide(Authentication authentication, Object object,
			Collection<ConfigAttribute> attributes)
			throws AccessDeniedException, InsufficientAuthenticationException {
		if (null == attributes)
			return;
		for (ConfigAttribute attribute : attributes) {
			String needRole = ((SecurityConfig) attribute).getAttribute();
			// authority为用户所被赋予的权限, needRole 为访问相应的资源应该具有的权限。
			for (GrantedAuthority grantedAuthority : authentication
					.getAuthorities()) {
				if (needRole.equals(grantedAuthority.getAuthority()))
					return;
			}
		}
		throw new AccessDeniedException("权限不足!");
	}

	public boolean supports(ConfigAttribute attribute) {
		return true;
	}

	public boolean supports(Class<?> clazz) {
		return true;
	}
}



SecurityMetadataSource是角色跟资源加载器,项目启动的时候会先执行资源跟角色关联加载提供给security以便认证

/**
 * 初始化时加载角色资源关联数据
 * 
 * @author shadow
 * @email 124010356@qq.com
 * @create 2012.04.28
 */
public class SecurityMetadataSourceExtendImpl implements
		SecurityMetadataSourceExtend {

	private boolean expire = false; // 过期标识

	private RoleService roleService; // 角色服务类

	private ResourceService resourceService; // 资源服务类

	private RequestMatcher requestMatcher; // 匹配规则

	private String matcher; // 规则标识

	private Map<String, Collection<ConfigAttribute>> kv = new HashMap<String, Collection<ConfigAttribute>>(); // 资源集合

	public RoleService getRoleService() {
		return roleService;
	}

	@javax.annotation.Resource
	public void setRoleService(RoleService roleService) {
		this.roleService = roleService;
	}

	public ResourceService getResourceService() {
		return resourceService;
	}

	@javax.annotation.Resource
	public void setResourceService(ResourceService resourceService) {
		this.resourceService = resourceService;
	}

	public boolean supports(Class<?> clazz) {
		return true;
	}

	// 初始化方法时候从数据库中读取资源
	// @PostConstruct
	public void init() {
		load();
	}

	public Collection<ConfigAttribute> getAllConfigAttributes() {
		Set<ConfigAttribute> attributes = new HashSet<ConfigAttribute>();
		for (Map.Entry<String, Collection<ConfigAttribute>> entry : kv
				.entrySet()) {
			attributes.addAll(entry.getValue());
		}
		return attributes;
	}

	public Collection<ConfigAttribute> getAttributes(Object object)
			throws IllegalArgumentException {
		HttpServletRequest request = ((FilterInvocation) object).getRequest();
		// System.out.println("requestUrl is " + request.getRequestURI());

		// 检测是否刷新了资源
		if (isExpire()) {
			// 清空原本资源
			kv.clear();
			expire = false;
		}

		// 如果资源Map为空的时候则重新加载一次
		if (null == kv || kv.isEmpty())
			load();

		// 检测请求与当前资源匹配的正确性
		Iterator<String> iterator = kv.keySet().iterator();
		while (iterator.hasNext()) {
			String uri = iterator.next();
			if (matcher.toLowerCase().equals("ant")) {
				requestMatcher = new AntPathRequestMatcher(uri);
			}
			if (matcher.toLowerCase().equals("regex")) {
				requestMatcher = new RegexRequestMatcher(uri, request
						.getMethod(), true);
			}
			if (requestMatcher.matches(request))
				return kv.get(uri);
		}
		return null;
	}

	/**
	 * 加载所有资源与权限的关系
	 */
	public void load() {
		List<Resource> resources = this.resourceService.loadForAll();
		for (Resource resource : resources) {
			List<Role> roles = this.roleService.findByResourceId(resource
					.getId());
			kv.put(resource.getContent(), list2Collection(roles));
		}
	}

	/**
	 * 将List<Role>集合转换为框架需要的Collection<ConfigAttribute>集合
	 * 
	 * @param roles
	 * @return Collection<ConfigAttribute>
	 */
	private Collection<ConfigAttribute> list2Collection(List<Role> roles) {
		List<ConfigAttribute> list = new ArrayList<ConfigAttribute>();
		for (Role role : roles)
			list.add(new SecurityConfig(role.getName()));
		return list;
	}

	public void setMatcher(String matcher) {
		this.matcher = matcher;
	}

	public boolean isExpire() {
		return expire;
	}

	public void expireNow() {
		this.expire = true;
	}

}


FilterSecurityInterceptor是资源访问第一个需要经过的过滤器,这个类我们还是不需要重写了,直接使用spring security提供的比较

具体路径org.springframework.security.web.access.intercept.FilterSecurityInterceptor


UserDetailsService这个类security的form表单登录处理

/**
 * SPRING SECURITY3用户登录处理
 * 
 * @author shadow
 * @email 124010356@qq.com
 * @create 2012.04.28
 */
public class UserDetailsServiceImpl implements UserDetailsService {

	private UserService userService;
	private RoleService roleService;

	public UserService getUserService() {
		return userService;
	}

	@Resource
	public void setUserService(UserService userService) {
		this.userService = userService;
	}

	public RoleService getRoleService() {
		return roleService;
	}

	@Resource
	public void setRoleService(RoleService roleService) {
		this.roleService = roleService;
	}

	public UserDetails loadUserByUsername(String username)
			throws UsernameNotFoundException {

		// 使用User服务类查询数据用户是否存在,如不存在或密码错误则抛出对应的异常
		List<User> users = this.userService.findByUserName(username);

		if (null == users || users.isEmpty())
			throw new UsernameNotFoundException("用户/密码错误,请重新输入!");

		User user = users.get(0);
		List<Role> roles = this.roleService.findByUserId(user.getId());
		if (null == roles || roles.isEmpty())
			throw new UsernameNotFoundException("权限不足!");
		// 把权限赋值给当前对象
		Collection<GrantedAuthority> gaRoles = new ArrayList<GrantedAuthority>();
		for (Role role : roles) {
			gaRoles.add(new SimpleGrantedAuthority(role.getName()));
		}
		user.setAuthorities(gaRoles);
		return user;
	}

}



三个类都准备好了现在去配置xml文件,先声明三个类的bean

        <!-- 自定义UserDetailsService认证  -->
	<bean id="userDetailsService"
		class="com.shadow.security.service.UserDetailsServiceImpl" />

	<!-- 自定义资源权限关系认证 -->
	<bean id="accessDecisionManager"
		class="com.shadow.security.service.AccessDecisionManagerImpl" />

	<!-- 自定义资源权限关系集合 -->
	<bean id="securityMetadataSource"
		class="com.shadow.security.service.SecurityMetadataSourceExtendImpl">
		<property name="matcher" value="ant" />
	</bean>



然后配置filterSecurityInterceptor,我们不再用security提供的实现类,而是使用我们刚刚写的实现类


<!-- 自定义认证管理,资源,权限  -->
	<bean id="filterSecurityInterceptor"
		class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
		<property name="authenticationManager"
			ref="authenticationManager" />
		<property name="accessDecisionManager"
			ref="accessDecisionManager" />
		<property name="securityMetadataSource"
			ref="securityMetadataSource" />
	</bean>


至于authenticationManager的注入如下(rememberMeAuthenticationProvider可不注入,这个东西是记住密码功能需要用到的玩意)


<!-- 认证管理器 -->
	<bean id="authenticationManager"
		class="org.springframework.security.authentication.ProviderManager">
		<property name="providers">
			<list>
				<ref bean="daoAuthenticationProvider" />
				<ref bean="rememberMeAuthenticationProvider" />
			</list>
		</property>
	</bean>

	<!-- 登录认证处理 -->
	<bean id="daoAuthenticationProvider"
		class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
		<property name="hideUserNotFoundExceptions" value="false"/>
		<property name="userDetailsService" ref="userDetailsService" />
		<property name="passwordEncoder" ref="passwordEncoder" />
		<property name="saltSource" ref="saltSource" />
	</bean>

	<!-- 加密方式 -->
	<bean id="passwordEncoder"
		class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" />

	<!-- 配置加密盐值 -->
	<bean id="saltSource"
		class="org.springframework.security.authentication.dao.ReflectionSaltSource">
		<property name="userPropertyToUse" value="username" />
	</bean>



然后配置我们的过滤链

<!-- 自定义SPRING SECURITY过滤链 -->
	<bean id="securityFilterChainProxy"
		class="org.springframework.security.web.FilterChainProxy">
		<constructor-arg>
			<list>
				<security:filter-chain pattern="/services/**"
					filters="none" />
				<security:filter-chain pattern="/test*" filters="none" />
				<security:filter-chain pattern="/**"
					filters="concurrentSessionFilter,securityContextPersistenceFilter,logoutFilter,usernamePasswordAuthenticationFilter,rememberMeAuthenticationFilter,sessionManagementFilter,anonymousAuthFilter,exceptionTranslationFilter,filterSecurityInterceptor" />
			</list>
		</constructor-arg>
	</bean>



至于过滤链里的其他filter我就不一一列出来了,然后大概流程就这样可以了,然后页面就搞个普通的security表单,提交的时候会进入到我们的userDetailsService实现类里验证你输入的账号密码是否一致,至于主要三个model就不出代码了,相信大家也应该明白,就是User,Role,Resource三者之间的关联


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值