最近项目开发中有这样一个业务逻辑,一个登陆画面,根据不同权限跳转到不同的画面(Action)
开始的做法是直接跳到一个调度的Action,再由这个Action去分配。
这次开发使用了安全框架,遂希望通过安全框架去做这个调度
于是使用authentication-success-handler-ref
来替换default-target-url和always-use-default-target,实现这一目的
国际惯例,先上代码
Xml代码
<http auto-config='true' >
<intercept-url pattern="/public/**" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/user/**" access="ROLE_SPACE_ADMIN,ROLE_SMALL_SPACE_ADMIN,ROLE_INSTITUTION_MEMBER,ROLE_SYSTEM_ADMIN"/>
<intercept-url pattern="/admin/**" access="ROLE_SUPER_ADMIN"/>
<form-login login-page="/user/login.action"
authentication-failure-url="/user/login.action?msg=fault"
authentication-success-handler-ref="authenticationDispatcher"
login-processing-url="/securityLogin"/>
<logout logout-success-url="/user/login.action" logout-url="/securityLogout"/>
</http>
<beans:bean id="authenticationDispatcher" class="com.lstp.service.security.impl.LstpAuthenticationSuccessHandler">
<beans:property name="authDispatcherMap">
<beans:ref local="dispatcherMap"/>
</beans:property>
</beans:bean>
<beans:bean id="dispatcherMap" class="java.util.HashMap">
<beans:constructor-arg>
<beans:map>
<beans:entry key="ROLE_SPACE_ADMIN" value="/user/userSpace.action"/>
<beans:entry key="ROLE_SMALL_SPACE_ADMIN" value="/user/userSpace.action"/>
<beans:entry key="ROLE_INSTITUTION_MEMBER" value="/user/userSpace.action"/>
<beans:entry key="ROLE_SYSTEM_ADMIN" value="/admin/adminSpace.action"/>
<beans:entry key="ROLE_SUPER_ADMIN" value="/admin/adminSpace.action"/>
</beans:map>
</beans:constructor-arg>
</beans:bean>
authentication-success-handler-ref="authenticationDispatcher"是至关重要的,当登陆成功会调用实现AuthenticationSuccessHandler接口的onAuthenticationSuccess方法.
下面是实现类
Java代码
package com.lstp.service.security.impl;
import java.io.IOException;
import java.util.Collection;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.util.Assert;
/**
* 权限登录成功句柄
* 该类为平台成功跳转到多个入口提供依据
* @author ryuu-kk
*
*/
public class LstpAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
/**
* url参数
*/
private Map<String, String> map;
/**
* 多role选择,默认取得权限表第一个权限
*/
private boolean isFirst = true;
@Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
Assert.notNull(map, "AuthInterceptMap is null!");
String url = "";
Collection<GrantedAuthority> authCollection = authentication.getAuthorities();
if (authCollection.isEmpty()) {
return;
}
//对于一个登录用户有多种角色,只取得第一个
if (isFirst) {
GrantedAuthority[] a = new GrantedAuthorityImpl[]{};
url = map.get(authCollection.toArray(a)[0].toString());
response.sendRedirect(request.getContextPath() + url);
return;
}
//选择取得最后一个role掉转;这里一个用户的多个角色较少
//迭代的速度比转换成数组的速度要快
for (GrantedAuthority auth : authCollection) {
url = map.get(auth.getAuthority());
}
response.sendRedirect(url);
}
/**
* 权限跳转依据
* @param map 参数
* key:url
* value:role
*/
public void setAuthDispatcherMap(Map<String, String> map) {
this.map = map;
}
/**
* 多种角色方案
* 设置是否只取得第一个role
* @param isFirst true:多种角色只取第一个,false:取得最后一个
*/
public void setMultipleAuth(boolean isFirst) {
this.isFirst = isFirst;
}
}