2006-10-08

Web应用中基于组的用户权限管理在Spring框架下的实现

Views: 23496 | 4 Comments

在几乎所有的web应用中都需要对访问者(用户)进行权限管理, 因为我们希望某些页面只对特定的用户开放, 以及某些操作只有符合身份的用户才能进行. 这之中涉及到了身份验证和权限管理. 只有单用户系统和多用户单权限系统才不需要权限管理.

在本文中, 使用了基于组的权限管理, 并在Spring框架下利用HandlerInterceptorAdapter和Hibernate进行实现.

User的结构是:

public class User {

	private int id;

	private String name;

	private String password;

	private Set<String> groups = new HashSet<String>();
}

UserGroup表:

user:int
group:String

使用联合主键, 在Java中没有对应的类.

Hibernate映射文件是:

<hibernate-mapping auto-import="true" default-lazy="false">
	<class name="net.ideawu.User" table="User">
		<cache usage="read-write" />
		<id name="id" column="id">
			<generator class="native"/>
		</id>
		<property name="name" column="name"/>
		<property name="password" column="password"/>
		<set name="groups" table="UserGroup" cascade="save-update" lazy="false">
			<key column="user" />
			<element column="`group`" type="string" />
		</set>
	</class>
</hibernate-mapping>

一切的身份验证交给一个继承HandlerInterceptorAdapter的类来做:

import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import org.springframework.web.util.UrlPathHelper;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
...

public class AuthorizeInterceptor extends HandlerInterceptorAdapter {

	private UrlPathHelper urlPathHelper = new UrlPathHelper();

	private PathMatcher pathMatcher = new AntPathMatcher();

	private  Properties groupMappings;

	/**
	 * Attach URL paths to group.
	 */
	public void setGroupMappings(Properties groupMappings) {
		this.groupMappings = groupMappings;
	}

	public boolean preHandle(HttpServletRequest request,
			HttpServletResponse response,
			Object handler) throws Exception {
		String url = urlPathHelper.getLookupPathForRequest(request);
		String group = lookupGroup(url);	// 找出资源所需要的权限, 即组名
		if(group == null){	// 所请求的资源不需要保护.
			return true;
		}
		// 如果已经登录, 一个User实例被保存在session中.
		User loginUser = (User)request.getSession().getAttribute("loginUser");
		ModelAndView mav = new ModelAndView("system/authorizeError");
		if(loginUser == null){
			mav.addObject("errorMsg", "你还没有登录!");
			throw new ModelAndViewDefiningException(mav);
		}else{
			if(!loginUser.getGroups().contains(group)){
				mav.addObject("errorMsg", "授权失败! 你不在 <b>" + group + "</b> 组!");
				throw new ModelAndViewDefiningException(mav);
			}
			return true;
		}
	}

	/*
	 * 查看 org.springframework.web.servlet.handler.AbstractUrlHandlerMapping.lookupHandler()
	 * Ant模式的最长子串匹配法.
	 */
	private String lookupGroup(String url){
		String group =  groupMappings.getProperty(url);
		if (group == null) {
			String bestPathMatch = null;
			for (Iterator it = this.groupMappings.keySet().iterator(); it.hasNext();) {
				String registeredPath = (String) it.next();
				if (this.pathMatcher.match(registeredPath, url) &&
							(bestPathMatch == null || bestPathMatch.length() <= registeredPath.length())) {
					group = this.groupMappings.getProperty(registeredPath);
					bestPathMatch = registeredPath;
				}
			}
		}
		return group;
	}
}

下面我们需要在Spring的应用上下文配置文件中设置:

<bean id="authorizeInterceptor" class="net.ideawu.AuthorizeInterceptor">
	<property name="groupMappings">
		<value>
			<!-- Attach URL paths to group -->
			/admin/*=admin
		</value>
	</property>
</bean>

<bean id="simpleUrlHandlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
	<property name="interceptors">
		<list>
			<ref bean="authorizeInterceptor" />
		</list>
	</property>
	<property name="mappings">
		<value>
			/index.do=indexController
			/browse.do=browseController
			/admin/removeArticle.do=removeArticleController
		</value>
	</property>
</bean>

注意到"/admin/*=admin", 所以/admin目录下的所有资源只有在admin组的用户才能访问, 这样就不用担心普通访客删除文章了. 使用这种方法, 你不需要在removeArticleController中作身份验证和权限管理, 一切都交给AuthorizeInterceptor.

Related posts:

  1. 使用ServletContextListener在服务器启动和关闭时创建和关闭缓存
  2. Spring MVC 入门
  3. MySQL 查询使用 Group By 的注意点
  4. 如何使用ServletContextListener
  5. 编写JSP/PHP+MySQL留言本
Posted by ideawu at 2006-10-08 20:10:23

4 Responses to "Web应用中基于组的用户权限管理在Spring框架下的实现"

  • 楼主你好:

    下面这段代码我不是很清楚能不能详细的说明一下,他们的作用,万分感谢!

    if (group == null) {

    String bestPathMatch = null;

    for (Iterator it = this.groupMappings.keySet().iterator(); it.hasNext();) {

    String registeredPath = (String) it.next();

    if (this.pathMatcher.match(registeredPath, url) &&

    (bestPathMatch == null || bestPathMatch.length() <= registeredPath.length())) {

    group = this.groupMappings.getProperty(registeredPath);

    bestPathMatch = registeredPath; Reply
  • 回复lornary: 你好.



    1. 不明白你的意思, 本文使用的正是重写preHandle()方法. 本文中如果用户授权失败, 会提示, 然后跳转.

    2. GroupMapping 本质上是一个哈希表(散列表, 键值对集合), 保存了URL(支持通配符)与组名的对应关系. 当用户访问某个URL时, Interceptor中查询该URL对应的组, 然后检查用户是否属于该组.

    Reply
  • 刚才我看错了,取groupMapping的url是什么? Reply
  • 看完这片文章我有如下几个问题:

    1. 为什么不只用preHandle,如果group为普通用户则跳转到首页,如果是管理员则跳转到后台管理页。

    2. 你的properties groupMapping和PathMatcher恕小弟浅薄,可否详细说明一下groupMapping的内容是什么?

    谢谢! Reply

Leave a Comment