Spring BlazeDS Integration之spring security(3)---自定义rememberMeServices,找到用户登陆成功切入点

仔细看过Spring BlazeDS Integration文档,我们知道,配置spring security其实很简单。

如下:


    

即可。但是这小小的 标记,其后台初始化了很多instance,其中最重要的就是

org.springframework.flex.security3.SpringSecurityLoginCommand    类,该类存在spring-flex-core-1.5.2.RELEASE.jar中,

之前提到过,等flex ui调用login api,请求会进入SpringSecurityLoginCommand.doAuthentication(String username, Object credentials)方法


我们来看看其具体实现:


    public Principal doAuthentication(String username, Object credentials) {
    	HttpServletRequest request = FlexContext.getHttpRequest();
    	HttpServletResponse response = FlexContext.getHttpResponse();
    	try {
    	    UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, extractPassword(credentials));
    	    setDetails(request, authRequest);
    	    
	        Authentication authentication = this.authManager.authenticate(authRequest);
	        if (authentication != null) {
	        	if (!isPerClientAuthentication() && request != null && response != null) {
	        		this.sessionStrategy.onAuthentication(authentication, request, response);
	        		this.rememberMeServices.loginSuccess(request, response, authentication); //注意这里
	        	}
	        	SecurityContextHolder.getContext().setAuthentication(authentication);
	        }
	        return authentication;
    	} catch (AuthenticationException ex) {
    	    SecurityContextHolder.clearContext();
    		if (request != null && response != null && !isPerClientAuthentication()) {
    			this.rememberMeServices.loginFail(request, response);
    		}
    		throw ex;
    	}
    }


可见此方法,让flex的login api 和spring sceurity 做了集成。让即使是flex ui传递过来的login请求也会走入到rememberMeServices当中去。

所以可以在rememberMeServices里做文章,找到用户登录成功后的切入点去,编写特殊逻辑。


修改security-config.xml:





	
		
		
		

	

	
		
		
	

	

	
		
		
	

	
		
			
				
				
				
			
		
	



自定义的rememberMeServices如下:


package test;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.flex.samples.contact.IContactDAO;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices;

public class MyRememberMeServices extends TokenBasedRememberMeServices {
	
	@Autowired
	private IContactDAO contactDAO;
	
	@Override
	public void onLoginSuccess(HttpServletRequest request,
			HttpServletResponse response,
			Authentication successfulAuthentication) {
		
		super.onLoginSuccess(request, response, successfulAuthentication);
		//SecurityContextHolder.getContext().setAuthentication(successfulAuthentication);
		System.out.println("Login Success:"+ contactDAO.findAll());  //登陆成功后,在这里实现自己的特殊逻辑
		
	}

}


注意:

  • rememberMeServices.loginSuccess(request, response, authentication); 不允许覆盖,
  • 但是loginSuccess()会调用onLoginSuccess() 方法,onLoginSuccess() 方法是允许覆盖的!
  • 自定义的rememberMeServices, 不管是http form提交,还是flex UI api提交,都会被调用。
  • 如果是http form提交,其调用顺序,会在authentication-success-handler-ref="simpleLoginSuccessHandler" /> 之后被调用

特别注意,如果在MyRememberMeServices.onLoginSuccess()中,所调用的dao方法是,被spring security所管理的话,当通过flex ui 登陆时,是会抱错的:

“Caused by: org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext"

两个解决办法,任选其一:

  1. 所调用的dao方法,不被spring security管理控制,spring security管理控制dao的上一级service层。
  2. 或者,在调用dao方法之前,加上此语句:SecurityContextHolder.getContext().setAuthentication(successfulAuthentication);




PS:org.springframework.flex.security3.SpringSecurityLoginCommand    类 其实也可以继承

然后在自己订制化的LoginCommand类,去找到登陆成功后的切入点。但是本人感觉很复杂,还没研究明白。

具体请看:http://docs.spring.io/spring-flex/docs/1.5.x/reference/html/#custom-login-command





你可能感兴趣的:(flex)