(本文转载自http://blog.csdn.net/meteorlWJ/archive/2009/09/13/4547759.aspx ,仅供自己学习参考)
文档下载地址: http://download.csdn.net/source/2559685 呵呵。。
在Spring MVC+BlazeDS+Flex框架实践:Database篇的基础上,这次要加入的是Spring Security的配置与应用。至于Spring Security的原理及配置详解网上已经有很多可参考的文章,在这里就不再重复了。
一、Spring Security配置
1)添加Application-Security.xml
在JAVA工程src下创建Application-Security.xml
<?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns:beans="http://www.springframework.org/schema/beans" xmlns="http://www.springframework.org/schema/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.4.xsd "> <http auto-config="true" session-fixation-protection="none" access-denied-page="/modules/common/403.jsp"> <form-login login-page="/modules/common/Index.html" authentication-failure-url="/modules/common/Index.html" default-target-url="/modules/common/Index.html" /> <logout logout-success-url="/modules/common/index.html" /> <intercept-url pattern="/modules/common/**" access="ROLE_ANONYMOUS" /> <intercept-url pattern="/messagebroker/**" access="ROLE_ANONYMOUS" /> <intercept-url pattern="/modules/admin/**" access="ROLE_ADMIN" /> <intercept-url pattern="/**" access="ROLE_USER" /> </http> <authentication-manager alias="authenticationManager" /> <authentication-provider user-service-ref="customUserDetailsService"> </authentication-provider> <beans:bean id="loggerListener" class="com.hand.common.security.SecurityLogListener"> <beans:property name="genericService" ref="genericService" /> </beans:bean> <beans:bean id="customLogoutFilter" class="org.springframework.security.ui.logout.LogoutFilter"> <custom-filter before="LOGOUT_FILTER" /> <beans:constructor-arg value="/"></beans:constructor-arg> <beans:constructor-arg> <beans:list> <beans:bean class="com.hand.common.security.SecurityLogoutHandler"> <beans:property name="genericService" ref="genericService" /> </beans:bean> </beans:list> </beans:constructor-arg> </beans:bean> <beans:bean id="customUserDetailsService" class="com.hand.common.security.FlexUserDetailsService"> <beans:property name="genericService" ref="genericService"></beans:property> <beans:property name="userNameProperty"> <beans:value>userName</beans:value> </beans:property> </beans:bean> </beans:beans>
2)修改web.xml
在添加Application-Security.xml后,需要在web.xml中将其添加到初始化加载列表中
修改web.xml以下配置:
<context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:ApplicationContext.xml,classpath:Application-Flex.xml,classpath:Application-hibernate.xml,classpath:Application-Security.xml </param-value> </context-param>
二、Security类创建
在JAVA工程src下创建package com.common.security
创建SecurityLogListener.java
package com.common.security;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.security.event.authentication.AbstractAuthenticationEvent;
import org.springframework.security.event.authentication.AuthenticationSuccessEvent;
import org.springframework.security.event.authentication.InteractiveAuthenticationSuccessEvent;
import org.springframework.security.ui.WebAuthenticationDetails;
import org.springframework.security.ui.session.HttpSessionApplicationEvent;
import org.springframework.security.ui.session.HttpSessionDestroyedEvent;
import com.common.hibernate.GenericService;
import flex.messaging.FlexContext;
public class SecurityLogListener implements ApplicationListener {
private static final Log logger = LogFactory.getLog(SecurityLogListener.class);
GenericService genericService;
public GenericService getGenericService() {
return genericService;
}
public void setGenericService(GenericService genericService) {
this.genericService = genericService;
}
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof AbstractAuthenticationEvent) {
try {
AbstractAuthenticationEvent authEvent = (AbstractAuthenticationEvent) event;
if (event instanceof AuthenticationSuccessEvent) {
Object obj = authEvent.getAuthentication().getPrincipal();
if (obj instanceof FlexUserDetails) {
System.out.println("Username: "+((FlexUserDetails) obj).getUsername());
System.out.println("Login Date: "+new Date());
System.out.println("Session Id: "+FlexContext.getFlexSession().getId());
}
} else if (event instanceof InteractiveAuthenticationSuccessEvent)
logger.warn("InteractiveAuthenticationSuccessEvent:" + authEvent.getAuthentication().getDetails());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else if (event instanceof HttpSessionApplicationEvent) {
HttpSessionApplicationEvent sessionEvent = (HttpSessionApplicationEvent) event;
if (event instanceof HttpSessionDestroyedEvent) {
logger.info("[destroy]"+sessionEvent.getSession().getId());
Map<String, Object> params = new HashMap<String, Object>();
params.put("sessionId", sessionEvent.getSession().getId());
System.out.println("Session Id: "+sessionEvent.getSession().getId());
System.out.println("Session remove date: "+new Date());
}else
logger.info("[create]"+sessionEvent.getSession().getId());
}
}
}
创建SecurityLogoutHandler.java
package com.common.security;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.Authentication;
import org.springframework.security.ui.logout.SecurityContextLogoutHandler;
import com.common.hibernate.GenericService;
public class SecurityLogoutHandler extends SecurityContextLogoutHandler {
private static final Log logger = LogFactory.getLog(SecurityLogoutHandler.class);
GenericService genericService;
public SecurityLogoutHandler() {
super();
}
public GenericService getGenericService() {
return genericService;
}
public void setGenericService(GenericService genericService) {
this.genericService = genericService;
}
public void logout(HttpServletRequest httpservletrequest, HttpServletResponse httpservletresponse,
Authentication authentication) {
try {
Map<String, Object> params = new HashMap<String, Object>();
params.put("sessionId", httpservletrequest.getSession().getId());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
super.logout(httpservletrequest, httpservletresponse, authentication);
}
}
创建FlexUserDetails.java
此类中的信息与数据库的结构有关
package com.common.security;
import java.util.Date;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.userdetails.UserDetails;
import com.admin.domain.FrameworkUser;
public class FlexUserDetails implements UserDetails {
private FrameworkUser fu;
private GrantedAuthority[] authorities;
public FlexUserDetails(FrameworkUser user,GrantedAuthority[] roles){
this.fu=user;
this.authorities=roles;
}
public GrantedAuthority[] getAuthorities() {
return authorities;
}
public String getPassword() {
return fu.getUserPassword();
}
public String getUsername() {
// TODO Auto-generated method stub
return fu.getUserName();
}
public boolean isAccountNonExpired() {
return true;
}
public boolean isAccountNonLocked() {
// TODO Auto-generated method stub
return true;
}
public boolean isCredentialsNonExpired() {
// TODO Auto-generated method stub
return true;
}
public boolean isEnabled() {
Date now=new Date();
return fu.getStartDateActive().before(now)&&(fu.getEndDateActive()==null||fu.getEndDateActive().after(now));
}
public FrameworkUser getFu() {
return fu;
}
public void setFu(FrameworkUser fu) {
this.fu = fu;
}
public void setAuthorities(GrantedAuthority[] authorities) {
this.authorities = authorities;
}
}
创建FlexUserDetailsService.java
此类中具体执行了用户登录时的授权等操作,其中明确了当用户为"admin"时,为其授予ROLE_ADMIN、ROLE_USER、ROLE_ANONYMOUS权限;而其他用户则只有ROLE_USER、ROLE_ANONYMOUS权限。不同权限的访问范围在Application-Security.xml中进行控制。本例中只有ROLE_ADMIN权限的角色才能访问modules/admin下的页面。
package com.common.security;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.dao.DataAccessException;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.GrantedAuthorityImpl;
import org.springframework.security.SpringSecurityMessageSource;
import org.springframework.security.userdetails.UserDetails;
import org.springframework.security.userdetails.UserDetailsService;
import org.springframework.security.userdetails.UsernameNotFoundException;
import com.admin.domain.FrameworkUser;
import com.common.hibernate.GenericService;
public class FlexUserDetailsService implements UserDetailsService {
private static final Logger logger = Logger.getLogger(AuthenticationHelper.class);
private GenericService genericService;
private String userNameProperty;
protected MessageSourceAccessor messages;
private String authoritiesbyUsernameQuery;
public FlexUserDetailsService() {
messages = SpringSecurityMessageSource.getAccessor();
}
public GenericService getGenericService() {
return genericService;
}
public void setGenericService(GenericService genericService) {
this.genericService = genericService;
}
public String getUserNameProperty() {
return userNameProperty;
}
public void setUserNameProperty(String userNameProperty) {
this.userNameProperty = userNameProperty;
}
public String getAuthoritiesbyUsernameQuery() {
return authoritiesbyUsernameQuery;
}
public void setAuthoritiesbyUsernameQuery(String authoritiesbyUsernameQuery) {
this.authoritiesbyUsernameQuery = authoritiesbyUsernameQuery;
}
public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException, DataAccessException {
System.out.println("UserDetails: loadUserByUsername");
List users = new ArrayList();
try {
users = this.loadUsersByUsername(name);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (users.size() == 0)
throw new UsernameNotFoundException(messages.getMessage("JdbcDaoImpl.notFound", new Object[] { name },
"Username {0} not found"), name);
FrameworkUser user = (FrameworkUser) users.get(0);
GrantedAuthority[] roles = loadUserAuthorities(name);
if (roles == null)
throw new UsernameNotFoundException(messages.getMessage("JdbcDaoImpl.noAuthority", new Object[] { name },
"User {0} has no GrantedAuthority"), name);
logger.info("roles " + roles.length);
logger.info("login in success," + user.getUserName());
return new FlexUserDetails(user, roles);
}
private List<Object> loadUsersByUsername(String name) throws Exception {
System.out.println("List<Object>: loadUserByUsername");
Map<String, Object> params = new HashMap<String, Object>();
params.put(this.userNameProperty, name);
return genericService.findByProperty(FrameworkUser.class.getName(), params);
}
private GrantedAuthority[] loadUserAuthorities(String name) {
Map params = new HashMap();
params.put("userName", name);
List<GrantedAuthority> roles = new ArrayList<GrantedAuthority>();
if(name.equals("admin")){
roles.add(new GrantedAuthorityImpl(name));
roles.add(new GrantedAuthorityImpl("ROLE_ANONYMOUS"));
roles.add(new GrantedAuthorityImpl("ROLE_ADMIN"));
roles.add(new GrantedAuthorityImpl("ROLE_USER"));
System.out.println("授权: ROLE_ADMIN,ROLE_ANONYMOUS");
}else{
roles.add(new GrantedAuthorityImpl(name));
roles.add(new GrantedAuthorityImpl("ROLE_ANONYMOUS"));
roles.add(new GrantedAuthorityImpl("ROLE_USER"));
System.out.println("授权: ROLE_USER,ROLE_ANONYMOUS");
}
GrantedAuthority[] authoritiesarray = new GrantedAuthority[roles.size()];
roles.toArray(authoritiesarray);
return authoritiesarray;
}
}
创建AuthenticationHelper.java
此类在用户登录时被调用
package com.common.security;
import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.Logger;
import org.springframework.security.Authentication;
import org.springframework.security.AuthenticationManager;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.context.SecurityContextHolder;
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
import org.springframework.security.userdetails.UserDetails;
import flex.messaging.FlexContext;
public class AuthenticationHelper {
private static final Logger logger = Logger.getLogger(AuthenticationHelper.class);
private AuthenticationManager authenticationManager;
public AuthenticationManager getAuthenticationManager() {
return authenticationManager;
}
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
public void authenticatePrincipal(String username, String password) {
//try{
logger.info("user login system! username:" + username);
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
username, password);
Authentication authentication = authenticationManager.authenticate(usernamePasswordAuthenticationToken);
SecurityContextHolder.getContext().setAuthentication(authentication);
GrantedAuthority[] authorities = SecurityContextHolder.getContext().getAuthentication().getAuthorities();
int numAuthorities = authorities.length;
String[] grantedRoles = new String[numAuthorities];
for (int counter = 0; counter < numAuthorities; counter++) {
grantedRoles[counter] = authorities[counter].getAuthority();
}
String name = SecurityContextHolder.getContext().getAuthentication().getName();
logger.info("登录成功!");
//}catch(Exception e){e.printStackTrace();}
}
public Map getCurrentUser() {
if (SecurityContextHolder.getContext() == null
|| SecurityContextHolder.getContext().getAuthentication() == null
|| SecurityContextHolder.getContext().getAuthentication().getPrincipal() == null) {
Map temp = new HashMap();
temp.put("userName", "System");
temp.put("userId", 0);
return temp;
}
Map user = new HashMap();
Object obj = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (obj instanceof UserDetails) {
user.put("userDescription", ((FlexUserDetails) obj).getFu().getUserDescription());
user.put("userId", ((FlexUserDetails) obj).getFu().getUserId());
user.put("userName", ((FlexUserDetails) obj).getUsername());
} else {
user.put("userName", obj.toString());
user.put("userId", -100);
}
logger.info(user);
return user;
}
public Long getCurrentUserId() {
if (this.getCurrentUser().get("userId") != null)
return Long.valueOf(this.getCurrentUser().get("userId").toString());
return new Long(-100);
}
}
三、配置AuthenticationHelper
1)发布AuthenticationHelper
在Application-Flex.xml中添加如下配置:
<bean id="authenticationHelper" class="com.hand.common.security.AuthenticationHelper"> <property name="authenticationManager" ref="authenticationManager"></property> <flex:remoting-destination /> </bean>
2)创建CommonModule.mxml
在FLEX工程modules/common目录下创建CommonModule.mxml,用以实现Security验证
<?xml version="1.0" encoding="utf-8"?> <mx:Module xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="500" height="300"> <mx:RichTextEditor x="0" y="0" title="Title" width="100%" height="100%"> </mx:RichTextEditor> </mx:Module>
3)引用authenticationHelper
在FLEX工程remoting-config.xml中添加如下配置
<destination id="authenticationHelper"> <properties> <source>authenticationHelper</source> </properties> </destination>
3)修改Index.mxml
在Index.mxml中调用authenticationHelper,修改后的Index.mxml内容如下:<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" horizontalAlign="center" creationComplete="initApp()" fontSize="15" > <mx:Script> <!--[CDATA[ import mx.rpc.events.FaultEvent; import mx.rpc.events.ResultEvent; import mx.controls.Alert; private function initApp():void{ UserService.getMessage(); UserService.getMessage.addEventListener(ResultEvent.RESULT, getMessageHandler); } private function getMessageHandler(evt:ResultEvent):void{ UserService.getMessage.removeEventListener(ResultEvent.RESULT, getMessageHandler); initText.text = evt.result as String; } private function login():void{ //添加登录成功监听器 authenticationHelper.authenticatePrincipal.addEventListener(ResultEvent.RESULT, loginSuccess); //添加登录失败监听器 authenticationHelper.authenticatePrincipal.addEventListener(FaultEvent.FAULT, loginFailure); //向服务器发送登录请求 authenticationHelper.authenticatePrincipal(username.text, password.text); } private function loginSuccess(event:Event):void { authenticationHelper.authenticatePrincipal.removeEventListener(ResultEvent.RESULT, loginSuccess); this.currentState='loginSuccess'; } private function loginFailure(event:FaultEvent):void { Alert.show("登录不成功!"+event.fault.faultString); authenticationHelper.removeEventListener(FaultEvent.FAULT, loginFailure); } private function changeState(sign:String):void{ currentState = 'moduleState'; if(sign=='A'){ currentState = 'moduleState'; moduleLoader.url = '../admin/UserModule.swf'; }else{ currentState = 'moduleState'; moduleLoader.url = '../common/CommonModule.swf'; } } private function logout():void{ navigateToURL(new URLRequest("javascript:location.href='TestProject/j_spring_security_logout';"), "_self"); } ]]--> </mx:Script> <mx:RemoteObject id="UserService" destination="UserService"/> <mx:RemoteObject id="authenticationHelper" destination="authenticationHelper"/> <mx:states> <mx:State name="loginSuccess"> <mx:RemoveChild target="{vbox1}"/> <mx:AddChild position="lastChild"> <mx:VBox width="50%" height="30%" horizontalAlign="center" verticalAlign="middle"> <mx:LinkButton label="admin.mxml" click="changeState('A')"/> <mx:LinkButton label="common.mxml" click="changeState('B')"/> </mx:VBox> </mx:AddChild> </mx:State> <mx:State name="moduleState"> <mx:RemoveChild target="{vbox1}"/> <mx:AddChild position="lastChild"> <mx:ModuleLoader width="50%" height="50%" id="moduleLoader" url="../admin/UserModule.swf"/> </mx:AddChild> <mx:AddChild position="lastChild"> <mx:LinkButton label="返回" click="currentState='loginSuccess'"/> </mx:AddChild> <mx:AddChild position="lastChild"> <mx:LinkButton label="退出" click="logout()"/> </mx:AddChild> </mx:State> </mx:states> <mx:Label text="Welcome" id="initText" fontWeight="bold"/> <mx:VBox width="50%" height="50%" horizontalAlign="center" verticalAlign="middle" id="vbox1"> <mx:FormItem label="用户名" labelWidth="100"> <mx:TextInput id="username" width="200"/> </mx:FormItem> <mx:FormItem label="密码" labelWidth="100"> <mx:TextInput id="password" width="200" displayAsPassword="true"/> </mx:FormItem> <mx:Button label="登录" width="80" click="login()"/> </mx:VBox> </mx:Application>
四、编译运行
1)编译FLEX工程
选择Project—>Clean—>TestProject
2)拷贝FLEX编译目录bin-debug/modules到JAVA工程WebRoot下
3)启动本地数据库
4)启动服务器
5)服务器正常启动后,在浏览器内输入(其中9090为服务器端口号)
http://localhost:9090/TestProject/modules/common/Index.html
运行结果:
以Sky用户登录