`
metadmin
  • 浏览: 168345 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

权限管理最佳实践:二,URL权限控制

阅读更多

-------------------------------------------- 总大纲 ---------------------------------

Ralasafe开源有段时间了,大约有2个月了。根据社区的反馈,我打算围绕Ralasafe最佳实践,书写一系列BLOG。

 

大体内容有:

1, 登录控制: 哪些页面需要登录后才能访问,登录用户名、密码验证,登录转向页面;

2, URL权限控制:哪些页面访问需要进行角色权限验证,怎样验证最简单有效,如何处理验证失败情况;

3, 数据级权限管理方案探讨:选择中间件呢还是框架?

4, Ralasafe体系结构: 用户怎么读取,用户有哪些字段,怎样与应用基础;

5, 数据级查询权限管理: 如何给不同的人分配不同的查询数据权限,返回where条件呢,还是直接返回结果集?

6, 数据级决策权限管理: 如何给不同的人分配不同的数据操作权限,当用户不具备权限怎么办?

7, 其他细小的权限控制: 如下拉框显示内容;按钮、链接是否显示,图片是否显示等。

-------------------------------------------- ------- --------------------------------

 

今天说的URL权限控制,内容主要有:URL权限控制,当用户访问某URL时,进行角色权限验证。如果有相应权限,则允许其正常访问;否则,转到拒绝页面。

我们依然通过一个Filter来实现,这样就无需在代码中增加权限判断,也无需套用任何框架。对于整个权限管理系统来说,本节内容也非常简单

理论分析

当软件实施人员进行系统实施的时候,会将一些访问菜单定义为权限。然后定义角色,让角色拥有权限。然后再将权限赋给用户。

所以,当用户请求某个URL的时候,要不该URL需要权限验证,要不就是不需要权限验证。

检验标准就是:看权限表里面有没有该URL。检验的时候,唯一需要注意的是:URL参数,比如employeeManage?op=add。

数据库模型

权限表:id<int>,name<varchar>,url<varchar>,description<varchar>   | pk(id)

角色表:id<int>,name<varchar>,description<varchar>                        | pk(id)

角色-权限关系表:roleId<int>,privilegeId<int>                                       | pk(roleId,privilegeId)

用户-角色关系表:userId<int>(根据你系统的情况,也可能是varchar等),roleId<int> | pk(userId,roleId)

Ralasafe方案

Ralasafe权限管理中间件(下载地址),既可以管理和控制功能级权限,也可以管理和控制数据级权限。开发者还可以根据需求,只选择功能级控制,或者只选择数据级控制。

 

安装好用户元数据的时候,Ralasafe自动创建所有权限表。相关权限数据,都由Ralasafe界面进行管理(即录入)。

 

Ralasafe的管理界面,在功能权限方面可以做到:

1,管理权限界面;

2,管理角色界面,并给角色赋权限;

3,给用户分配角色界面。这里还需要注意:不同用户管理可以给不同范围的用户分配角色。比如:总公司的管理员可以给所有人分配角色;分公司管理员可以给本分公司及下属子公司用户分配角色。

 

Ralasafe将最后一点视为数据级权限。详见:http://www.ralasafe.org/zh/guide/reference/safe.html#ralasafe 和

http://www.ralasafe.org/jforum/posts/list/11.page

 

org.ralasafe.webFilter.UrlAclFilter配置到web.xml即可,而且配置工作量极其少。

 

<filter>
	<filter-name>ralasafe/UrlAclFilter</filter-name>
	<filter-class>org.ralasafe.webFilter.UrlAclFilter</filter-class>
	<init-param>
		<param-name>loginPage</param-name>
		<param-value>/ralasafe/demo/login.jsp</param-value>
	</init-param>
	<init-param>
		<param-name>denyPage</param-name>
		<param-value>/ralasafe/demo/noPrivilege.jsp</param-value>
	</init-param>
</filter>
<filter-mapping>
	<filter-name>ralasafe/UrlAclFilter</filter-name>
	<url-pattern>/ralasafe/demo/*</url-pattern>
</filter-mapping>
 

 

该Filter具有这些功能:

1,在用户具有权限的时候,正常访问;

2,在用户不具有权限的时候,转到拒绝页面;

3,如果用户没用登录,转到登录页面,让用户先登录。

其他

这里我简单说说spring security。

spring security在控制功能权限的时候,还会帮助开发人员控制Dao/Service等组件。我个人认为这种控制是多余的。

因为,功能权限控制应该站在最终用户角度进行考虑。Dao/Service等编程开发级的组件,并不是最终用户关心的事情。所以无需进行功能权限控制。

另外,大家在使用spring security,我建议将功能级权限控制放在数据库里面,而不是annotation到java code里面。因为annotation到java code里面,最终用户就不能控制了。

 

注:ralasafe团队博客在javaeye/baidu/blogjava等空间,同步发布。ralasafe官方网站:http://www.ralasafe.org/zh

 

 

 

分享到:
评论
6 楼 lzmhehe 2010-09-08  
替楼主叫屈
看不明白那些投新手帖的
权限真的那么简单吗?

5 楼 jqyp324 2010-09-07  
权限是最讨厌的
4 楼 jenight 2010-09-04  
粒度太粗了,这让我想起当年研究RBAC的日子。
那时候的导师要求需要将每个页面的每一个按钮都作为可控制部分,
而我那时也只是简单用url作为最小粒度,不过现在想一想还真对不起RBAC。
3 楼 metadmin 2010-09-03  
jxzchh 写道
不好部署,能否有文档说明下部署流程。

Ralasafe手册
第2章讲解了怎样安装。非常简单,就是复制文件,修改数据库配置文件和用户元数据文件。
2 楼 melin 2010-09-03  
spring security扩展,从数据库读取信息。从新实现UserDetailsService和FilterInvocationSecurityMetadataSource
public class HibernateUserDetailsServiceImpl extends HibernateDaoSupport implements UserDetailsService {

	//~ Methods ========================================================================================================
	@SuppressWarnings("unchecked")
	public UserDetails loadUserByUsername(String userId)
			throws UsernameNotFoundException, DataAccessException {
		List results = getHibernateTemplate().find("from User as res left outer join fetch res.employee left outer join fetch res.authorities where userId = ?",
                new Object[] {userId});
		if (results.size() < 1) {
            throw new UsernameNotFoundException(userId + "not found");
        }

		return (UserDetails) results.get(0);
	}
}


public class HibernateFilterInvocationSecurityMetadataSource extends HibernateDaoSupport
		implements FilterInvocationSecurityMetadataSource{
	
	//~ Static fields ==================================================================================================
	public static final String CACHE_KEY = "FilterInvoSecMetaKey";

	//~ Instance fields ================================================================================================
	protected final Logger logger = LoggerFactory.getLogger(this.getClass());
	
	@javax.annotation.Resource(name="starFrameCache")
	private Cache cache;
	
	private Map<Object, Collection<ConfigAttribute>> httpMap = null;

	private UrlMatcher urlMatcher = new AntUrlPathMatcher(true);

    private boolean stripQueryStringFromUrls;
	
	//~ Constructors ===================================================================================================

	//~ Methods ========================================================================================================
    /**
     * 初始化,加载资源权限 
     */
    @SuppressWarnings("unchecked")
	@PostConstruct
	public void loadSecurityMetadataSource() throws Exception {
    	logger.info("Loading Security Metadata Source...");
    	
    	httpMap = new LinkedHashMap<Object, Collection<ConfigAttribute>>();
    	
    	Session session = getHibernateTemplate().getSessionFactory().openSession();
    	Query query = session.createQuery("from Resource as res left outer join fetch res.roles where res.enabled = :enabled and res.type <> :type order by res.priority");
    	query.setCharacter("enabled", 'Y');
    	//不等于method类型
    	query.setString("type", Resource.ResourceType.METHOD.getType());
		List<Resource> resources = query.list();
		
		for(Resource resource : resources) {
			String pattern = resource.getAction();
			//如果资源是菜单类型时,需要去掉前缀
			if(pattern.startsWith("./"))
				pattern = pattern.substring(1);
			else if(pattern.startsWith("../"))
				pattern = pattern.substring(2);
			
			while(pattern.startsWith("/..")) {
				pattern = pattern.substring(3);
			}
				
			List<ConfigAttribute> attrs = new ArrayList<ConfigAttribute>();
			Set<Role> roles = resource.getRoles();
	    	
			for(Role role : roles) {
				attrs.add(new SecurityConfig(role.getCode()));
			}
			httpMap.put(urlMatcher.compile(pattern), attrs);

			if (logger.isDebugEnabled()) {
	            logger.debug("Added URL pattern: " + pattern + "; attributes: " + attrs);
	        }
		}
		session.close();
		
		cache.putItem(CACHE_KEY, httpMap);
	}
	
	/**
	 * 
	 */
	public Collection<ConfigAttribute> getAllConfigAttributes() {
		return null;
	}

	/**
	 * 通过FilterInvocation对象查找适合的ConfigAttribute
	 * 
	 * @param object
	 * @return
	 */
	public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
		if ((object == null) || !this.supports(object.getClass())) {
            throw new IllegalArgumentException("Object must be a FilterInvocation");
        }

        String url = ((FilterInvocation) object).getRequestUrl();

        return lookupAttributes(url);
	}
	
	/**
	 * 
	 * @param url
	 * @return
	 */
	public final Collection<ConfigAttribute> lookupAttributes(String url) {
        if (stripQueryStringFromUrls) {
            // Strip anything after a question mark symbol, as per SEC-161. See also SEC-321
            int firstQuestionMarkIndex = url.indexOf("?");

            if (firstQuestionMarkIndex != -1) {
                url = url.substring(0, firstQuestionMarkIndex);
            }
        }

        if (urlMatcher.requiresLowerCaseUrl()) {
            url = url.toLowerCase();

            if (logger.isDebugEnabled()) {
                logger.debug("Converted URL to lowercase, from: '" + url + "'; to: '" + url + "'");
            }
        }

        // Obtain the map of request patterns to attributes for this method and lookup the url.
        Object obj = cache.getItem(CACHE_KEY);
        if(obj == null) {
    		try {
				loadSecurityMetadataSource();
			} catch (Exception e) {
				e.printStackTrace();
			}
        }
        Collection<ConfigAttribute> attributes = extractMatchingAttributes(url, httpMap);

        return attributes;
    }
	
	/**
	 * 
	 * @param url
	 * @param map
	 * @return
	 */
	private Collection<ConfigAttribute> extractMatchingAttributes(String url, Map<Object, Collection<ConfigAttribute>> map) {

        final boolean debug = logger.isDebugEnabled();

        for (Map.Entry<Object, Collection<ConfigAttribute>> entry : map.entrySet()) {
            Object p = entry.getKey();
            boolean matched = urlMatcher.pathMatchesUrl(entry.getKey(), url);

            if (debug) {
                logger.debug("Candidate is: '" + url + "'; pattern is " + p + "; matched=" + matched);
            }

            if (matched) {
                return entry.getValue();
            }
        }
        return null;
    }

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

	public void setCache(Cache cache) {
		this.cache = cache;
	}
}

1 楼 jxzchh 2010-09-02  
不好部署,能否有文档说明下部署流程。

相关推荐

    PHP权限管理系统源代码

    通过研究这个【PHP权限管理系统源代码】,开发者不仅可以学习到如何在PHP中实现权限控制,还可以掌握如何构建一个完整的Web应用程序,包括用户认证、数据库操作、路由设计以及安全实践等多个方面。这对于提升PHP开发...

    基于C#+ASP.NET实现的通用权限管理系统(FrameWork) 1.0.5 源码发布

    通过研究这个源码包,开发者不仅可以学习到如何在ASP.NET环境中构建权限管理系统的最佳实践,还能了解到C#编程语言以及.NET Framework的相关知识,这对于提升Web应用开发技能是非常有价值的。同时,对于需要搭建自己...

    java权限管理系统

    Apache Shiro是一个强大且易用的Java安全框架,处理认证(身份验证)、授权(权限授权)以及会话管理和加密等功能。在这个基于Shiro的权限管理系统中,主要涉及以下几个关键知识点: 1. **认证**:认证是确定用户...

    通用权限管理的后台源码

    综上所述,"通用权限管理的后台源码"是一套完整的权限管理系统,它涉及到了用户认证、权限授权、角色管理等多个方面,采用Java技术栈并可能利用Spring Security等工具来实现。通过深入理解并研究这套源码,开发者...

    单点登录系统(SSO)+权限管理

    权限管理通常通过RBAC(Role-Based Access Control)模型实现,确保用户只能访问他们被授权的资源。 4. **源码分析**:`smart-master`可能代表了项目的主分支或主目录。在源码中,开发者可以找到认证和授权的相关...

    MVC的Action权限管理

    - 避免硬编码权限:应将权限信息存储在数据库中,方便管理和更新。 - 定期审计:检查和更新权限配置,确保其与业务需求一致。 - 加密敏感数据:用户密码和其他敏感信息应加密存储。 - 使用HTTPS:确保通信过程的...

    ASP.NET通用权限管理系统1.0

    10. **文档与教程**:如51aspx源码必读.txt,可能包含系统的使用指南、开发文档或者最佳实践。 11. **更新与支持**:"最新Asp.Net源码下载.url"可能指向系统更新或升级的链接,便于获取最新的版本和修复补丁。 在...

    基于Python的Flask WEB框架实现后台权限管理系统

    资源管理涉及对系统内可访问的URL或特定功能的控制。通过定义资源和权限之间的关系,可以决定哪些用户或角色可以访问哪些资源。这通常通过装饰器完成,例如在视图函数上添加装饰器来限制访问。 机构管理则涉及到...

    基于shiro前后端分离分布式权限管理(完整后端代码)

    总之,这个基于Shiro的分布式权限管理系统结合了现代Web开发的最佳实践,利用Shiro的强大功能和Redis集群的高效缓存,实现了安全、高效的用户权限管理。在实际开发中,这样的架构可以为大型互联网应用提供稳定、可...

    SpringBoot+Shiro权限管理系统脚手架.zip

    - 安全最佳实践:遵循安全编码原则,定期更新依赖库,防止SQL注入、XSS攻击等。 总结,SpringBoot+Shiro的结合为权限管理提供了一个高效且易于扩展的解决方案。通过合理的配置和设计,可以构建出满足各种需求的...

    OA办公软件三层架构权限管理

    - **51Aspx源码必读.txt**:可能包含关于51Aspx平台的源码阅读指南或最佳实践。 - **最新Asp.Net源码下载.url**:指向Asp.Net最新源码下载的链接。 - **MyOA、WFOA**:可能是两个不同的OA办公软件实例或模块。 -...

    Tomcat最佳实践T.omcat最佳实践

    Apache Tomcat是一款广泛使用的开源Servlet容器...这些最佳实践旨在帮助开发者和运维人员更好地管理和优化Tomcat服务器,以达到高性能、高可用性和安全性。理解并应用这些实践对于提升Web应用的稳定性和效率至关重要。

    java禁止直接url访问图片

    标题“Java禁止直接URL访问图片”涉及到的是网络资源保护和权限控制的问题,主要知识点包括: 1. **HTTP请求与响应**: 当用户通过浏览器或其他客户端工具输入一个URL来访问图片时,实际上是发送了一个HTTP GET...

    java后台管理系统,集成权限管理.zip

    Java后台管理系统是一个基于Java编程语言开发的用于企业管理的软件系统,通常包含用户管理、角色管理、权限控制等功能,旨在提供高效、安全的企业级业务处理能力。这个压缩包"java后台管理系统,集成权限管理.zip"很...

    基于SpringBoot3开发的通用后台权限管理系统,简单易用,快速上手资源来源网络以及部分开源社区仅供参考与学习项目不可商用、

    同时,网络上的博客、视频教程等也是学习的好资源,可以帮助快速理解和掌握SpringBoot3的新特性和最佳实践。 【项目不可商用】 本项目声明仅供学习和参考,不应用于商业用途。这主要是因为开源项目可能存在版权...

    C# 通用的权限系统管理

    此外,我们还可以利用ASP.NET的授权机制,通过Web.config配置文件或代码来设置URL级别的权限控制。例如,限制只有管理员角色才能访问特定的控制器或动作: ```xml *"/&gt; ``` 在实际项目中,我们还需要...

    Acegi安全权限管理手册

    Acegi的安全模型允许精细的权限控制,可以基于角色、URL、方法甚至业务对象进行授权。它使用AOP(面向切面编程)来实现权限检查,可以在任何代码执行点进行安全拦截。 4. **会话管理(Session Management)**: ...

    Spring Security 安全权限管理手册

    5. **最佳实践篇**:分享实际项目中的权限管理经验。 - 实战案例分析:提供具体场景下的权限管理方案。 - 常见问题解答:针对开发者在使用 Spring Security 过程中遇到的问题给出解决方案。 #### 三、第三方依赖...

    10_vue项目最佳实践1

    Vue.js项目最佳实践涵盖多个关键领域,包括项目配置、权限管理、导航菜单、数据mock测试以及webpack的定制化。在创建Vue项目时,利用Vue CLI 3.0可以帮助我们快速搭建一个规范化的开发环境。以下是一些核心知识点的...

Global site tag (gtag.js) - Google Analytics