论坛首页 Java企业应用论坛

帮Spring security一个忙:为Struts2 写个Plugin对Action进行权限控制

浏览 21798 次
精华帖 (0) :: 良好帖 (7) :: 新手帖 (10) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-06-08   最后修改:2009-10-19
你想拥有这样的功能吗?
public class TestAction extends ActionSupport {

	@ActionRoles( { "ROLE_ADMIN", "ROLE_USER" })
	public String test() throws Exception {
		return SUCCESS;
	}
}

进行以上配置后,只有拥有了“ROLE_ADMIN”,“ROLE_USER”两种角色的用户才能访问test这个action。
我们都知道Spring security拥有注解@Secured可以保护领域方法,但却无法实现Action的保护,因为Struts2中Action的执行已经涉及到Struts2本身的拦截器,已经与Spring Security过滤器无关了。所以想拥有上述功能,就只好自己写了。

现在你就能拥有!
首先,定义一个简单的注解:
@Target(METHOD)
@Retention(RUNTIME)
public @interface ActionRoles {
	String[] value();
}

然后,写个Struts2的拦截器,对请求进行拦截,像这样:
/**
 * @author PanHuizhi
 * 
 */

public class SpringSecurityInterceptor extends AbstractInterceptor {

	private static final long serialVersionUID = 1L;

	private String loginPage;
	private String accessDeniedPage;

	public String intercept(ActionInvocation actionInvocation) throws Exception {
		ActionRoles actionRole = getActionRole(actionInvocation);
		UserDetails userDetails = getUserDetails();
		Object savedPath = getPath();
		if (savedPath != null && userDetails != null) {
			removePath();
			return "!" + savedPath;
		}
		if (actionRole == null) {
			return actionInvocation.invoke();
		}
		if (userDetails == null) {
			putPath();
			return "!" + loginPage;
		}
		if (!isAccessable(userDetails.getAuthorities(), actionRole.value())) {
			return "!" + accessDeniedPage;
		}
		return actionInvocation.invoke();
	}

	private ActionRoles getActionRole(ActionInvocation actionInvocation) {
		ActionProxy actionProxy = actionInvocation.getProxy();
		Object action = actionProxy.getAction();
		String method = actionProxy.getMethod();
		Method actionMethod = null;
		try {
			actionMethod = action.getClass().getMethod(method);
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		}
		return actionMethod.getAnnotation(ActionRoles.class);
	}

	private UserDetails getUserDetails() {
		UserDetails userDetails = null;
		try {
			userDetails = (UserDetails) SecurityContextHolder.getContext()
					.getAuthentication().getPrincipal();
		} catch (Exception exception) {
		}
		return userDetails;
	}

	private void putPath() {
		ActionContext.getContext().getSession().put("SAVED_SERVLET_PATH",
				ServletActionContext.getRequest().getServletPath());
	}

	private String getPath() {
		return (String) ActionContext.getContext().getSession().get(
				"SAVED_SERVLET_PATH");
	}

	private void removePath() {
		ActionContext.getContext().getSession().remove("SAVED_SERVLET_PATH");
	}

	private boolean isAccessable(GrantedAuthority[] grantedAuthority,
			String[] roles) {
		List<String> grantedAuthorities = new ArrayList<String>();
		for (int i = 0; i < grantedAuthority.length; i++) {
			grantedAuthorities.add(grantedAuthority[i].getAuthority());
		}
		for (int i = 0; i < roles.length; i++) {
			if (!grantedAuthorities.contains(roles[i])) {
				return false;
			}
		}
		return true;
	}

	public void setLoginPage(String loginPage) {
		this.loginPage = loginPage;
	}

	public void setAccessDeniedPage(String accessDeniedPage) {
		this.accessDeniedPage = accessDeniedPage;
	}
}

最后,你只要做简单配置就大功告成了
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
        "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
	<package name="app-default" extends="struts-default">
		<result-types>
			<result-type name="direct"
				class="org.apache.struts2.spring.security.dispatcher.DirectResult"></result-type>
		</result-types>

		<interceptors>
			<interceptor name="springSecurityInterceptor"
				class="org.apache.struts2.spring.security.interceptor.SpringSecurityInterceptor">
				<param name="loginPage">/login.action</param>
				<param name="accessDeniedPage">/403.jsp</param>
			</interceptor>
			<interceptor-stack name="appDefaultStack">
				<interceptor-ref name="springSecurityInterceptor" />
				<interceptor-ref name="defaultStack" />
			</interceptor-stack>
		</interceptors>
		<default-interceptor-ref name="appDefaultStack" />

		<global-results>
			<result name="*" type="direct" />
		</global-results>
	</package>
</struts>

你需要根据实际情况修改“/login.action”,“/403.jsp”,接着只要你的Struts Package 都继承这个app-default包就行了啊,是不是很简单,保护Struts2的Action你现在就能拥有。
   发表时间:2009-06-08  
引用

经过测试发现,这个东西做的很不完善,很希望大家多多挑毛病,以后改进喔。。。。。

不完善就拿上来,为什么不做的完善再拿来show!!
0 请登录后投票
   发表时间:2009-06-08  
kjj 写道
引用

经过测试发现,这个东西做的很不完善,很希望大家多多挑毛病,以后改进喔。。。。。

不完善就拿上来,为什么不做的完善再拿来show!!

谦虚都不懂,算了,我把它删了,还不行嘛?
0 请登录后投票
   发表时间:2009-06-08   最后修改:2009-06-08
phz50 写道
kjj 写道
引用

经过测试发现,这个东西做的很不完善,很希望大家多多挑毛病,以后改进喔。。。。。

不完善就拿上来,为什么不做的完善再拿来show!!

谦虚都不懂,算了,我把它删了,还不行嘛?

引用

我们都知道Spring security拥有注解@Secured可以保护领域方法,但却无法实现Action的保护

大名鼎鼎的ss 竟然无法保护action ,怪哉!!
看来这句才知道,说得没错,果然不完善!!
0 请登录后投票
   发表时间:2009-06-08   最后修改:2009-06-08
引用
大名鼎鼎的ss 竟然无法保护action ,怪哉!!
看来这句才知道,说得没错,果然不完善!!
0 请登录后投票
   发表时间:2009-06-09  
LZ已经提供了很好的思路,但是按这个思路走下去,不搞的几天出不来东西啊。
0 请登录后投票
   发表时间:2009-06-09  
spring针对url的保护不就是针对action的保护吗,有这必要在搞一遍注释?
0 请登录后投票
   发表时间:2009-06-09   最后修改:2009-06-09
cris_jxg 写道
spring针对url的保护不就是针对action的保护吗,有这必要在搞一遍注释?

提的很好,不过,一个Action可以针对不同Url,而且Url是可能经常修改的,一旦修改了,就要修改它保护的配置了,维护起来很麻烦,特别是当Url较多时,而针对Action本身注解,一旦更改了Action或Url不用修改其它,维护起来比较方便和直观。当然也可以一起使用它们,并不冲突的。
0 请登录后投票
   发表时间:2009-06-09  
适用面太窄了,你这个是在代码里写死的,如果客户要调整权限怎么办
0 请登录后投票
   发表时间:2009-06-09  
fuwang 写道
适用面太窄了,你这个是在代码里写死的,如果客户要调整权限怎么办

?,可能你还不太明白,这个东西的功能,权限是通过对Action方法注解设置的,随时可以更改的,如把,@ActionRoles( { "ROLE_ADMIN", "ROLE_USER" }) ,改成@ActionRoles( { "ROLE_ADMIN"}) ,权限就改了啊
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics