论坛首页 编程语言技术论坛

FlexDS 与 Spring Security 的完美结合

浏览 5925 次
精华帖 (2) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2008-10-15  
最近一直在思考这个问题,网上也查了,资料也读了。放一个我自己写的SpringSecurityLoginCommand以备日后查阅。

package flex.spring;

import java.security.Principal;
import java.util.List;
import javax.servlet.ServletConfig;

import flex.messaging.FlexContext;
import flex.messaging.security.LoginCommand;
import flex.messaging.security.SecurityException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.Authentication;
import org.springframework.security.AuthenticationException;
import org.springframework.security.context.SecurityContext;
import org.springframework.security.context.SecurityContextHolder;
import org.springframework.security.context.SecurityContextImpl;
import org.springframework.security.providers.AuthenticationProvider;
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

/**
* Custom implementation of BlazeDS LoginCommand which utilizes
* Spring Security 2.0 framework underneath.
* <p/>
*
* Date: Oct 14, 2008
* Time: 12:33:46 PM
*/
public class SpringSecurityLoginCommand implements LoginCommand {
  protected final Log log = LogFactory.getLog(getClass());

  public static final String AUTHENTICATION_PROVIDER_BEAN_NAME = "authenticationProvider";
  public static final String SPRING_SECURITY_CONTEXT_KEY = "SPRING_SECURITY_CONTEXT";

  private final AuthenticationProvider provider;
  private final boolean isPerClientAuthentication;

  public SpringSecurityLoginCommand() {
    isPerClientAuthentication = FlexContext.isPerClientAuthentication();

    WebApplicationContext wac = WebApplicationContextUtils
        .getWebApplicationContext(FlexContext.getServletContext());

    provider = (AuthenticationProvider) wac.getBean(AUTHENTICATION_PROVIDER_BEAN_NAME);
    log.info("Spring Security Authentication Provider initialized - " + provider);
  }

  public Principal doAuthentication(String username, Object credentials) {
    SecurityContext securityContext;

    if (isPerClientAuthentication) {
      securityContext = (SecurityContext) FlexContext.getFlexClient()
          .getAttribute(SPRING_SECURITY_CONTEXT_KEY);

    } else {
      securityContext = (SecurityContext) FlexContext.getFlexSession()
          .getAttribute(SPRING_SECURITY_CONTEXT_KEY);
    }

    Authentication principal;

    if (securityContext == null) {
      UsernamePasswordAuthenticationToken token =
          new UsernamePasswordAuthenticationToken(username, credentials);

      try {
        principal = provider.authenticate(token);

        securityContext = new SecurityContextImpl();
        securityContext.setAuthentication(principal);

        if (isPerClientAuthentication) {
          FlexContext.getFlexClient().setAttribute(SPRING_SECURITY_CONTEXT_KEY, securityContext);
        } else {
          FlexContext.getFlexSession().setAttribute(SPRING_SECURITY_CONTEXT_KEY, securityContext);
        }

        if (log.isDebugEnabled()) {
          log.debug("[Login] Security Context was created.");
        }

      } catch (AuthenticationException e) {

        SecurityException se = new SecurityException();
        se.setMessage(SecurityException.SERVER_AUTHENTICATION_CODE);
        se.setRootCause(e);
        throw se;
      }

    } else {

      principal = securityContext.getAuthentication();

      log.info("[" + username + "] was already authenticated previously.");
    }

    SecurityContextHolder.setContext(securityContext);

    return principal;
  }

  public boolean logout(Principal principal) {
    if (isPerClientAuthentication) {
      FlexContext.getFlexClient().removeAttribute(SPRING_SECURITY_CONTEXT_KEY);
    } else {
      FlexContext.getFlexSession().removeAttribute(SPRING_SECURITY_CONTEXT_KEY);
    }

    SecurityContextHolder.getContext().setAuthentication(null);

    if (log.isDebugEnabled()) {
      log.debug("[Logout] Security Context was removed.");
    }

    return true;
  }

  public boolean doAuthorization(Principal principal, List list) {
    // always return TRUE as the authorization is delegated to Spring Security.
    return true;
  }

  public void start(ServletConfig config) {
    // noop
  }

  public void stop() {
    // noop
  }
}

services-config.xml------------------------------

<?xml version="1.0" encoding="ISO-8859-1"?>
<services-config>

    <services>
        <service-include file-path="remoting-config.xml" />
    </services>

    <factories>
        <factory id="spring" class="adobe.flex.sample.SpringFactory" />
    </factories>

    <security>
        <login-command class="flex.spring.SpringSecurityLoginCommand" server="all">
          <per-client-authentication>true</per-client-authentication>
        </login-command>
        <security-constraint id="default">
            <auth-method>Custom</auth-method>
        </security-constraint>
    </security>

    <channels>

        <channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel">
            <endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/amf"
                      class="flex.messaging.endpoints.AMFEndpoint"/>
        </channel-definition>
    </channels>

    <logging>
        <target class="flex.messaging.log.ConsoleTarget" level="Info">
            <properties>
                <prefix>[BlazeDS] </prefix>
                <includeDate>false</includeDate>
                <includeTime>false</includeTime>
                <includeLevel>true</includeLevel>
                <includeCategory>true</includeCategory>
            </properties>
            <filters>
                <pattern>Endpoint.*</pattern>
                <pattern>Service.*</pattern>
                <pattern>Configuration</pattern>
            </filters>
        </target>
    </logging>

    <system>
        <redeploy>
            <enabled>false</enabled>
        </redeploy>
    </system>

</services-config>

remoting-config.xml-----------------------------

<?xml version="1.0" encoding="ISO-8859-1"?>
<service id="remoting-service"
    class="flex.messaging.services.RemotingService">

    <adapters>
        <adapter-definition id="java-object"
           class="flex.messaging.services.remoting.adapters.JavaAdapter" default="true"/>
    </adapters>

    <default-channels>
        <channel ref="my-amf"/>
    </default-channels>

    <destination id="roles">
        <properties>
          <factory>spring</factory>
          <source>roles</source>
          <scope>session</scope>
        </properties>
        <security>
            <security-constraint ref="default" />
        </security>
    </destination>

</service>

spring-config.xml------------------------------
<?xml version="1.0" encoding="ISO-8859-1"?>

<beans xmlns="http://www.springframework.org/schema/beans"
       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.xsd">

  <bean id="authenticationProvider"
        class="org.springframework.security.providers.dao.DaoAuthenticationProvider">
    <property name="userDetailsService">
      <bean class="org.springframework.security.userdetails.memory.InMemoryDaoImpl">
        <property name="userMap">
          <value>
            david=password,ROLE_ADMIN
            alex=password,ROLE_USER
          </value>
        </property>
      </bean>
    </property>
  </bean>

  <bean id="hello" class="flex.spring.SecurityRoles" />

</beans>

java ------------------------
package flex.spring;

import org.springframework.security.Authentication;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.context.SecurityContextHolder;

public class SecurityRoles {

  public String allowedAuthorities() {
    Authentication principal = SecurityContextHolder.getContext().getAuthentication();
    StringBuilder result = new StringBuilder();
    for (GrantedAuthority ga : principal.getAuthorities()) {
      result.append(",").append(ga.getAuthority());
    }
    return result.substring(1);
  }
}

Flex Client---------------------------------------
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" width="100%" height="100%"
creationComplete="init()">

  <mx:Script>
  <![CDATA[
  import mx.controls.Alert;
import mx.messaging.config.ServerConfig;
import mx.rpc.AsyncToken;
import mx.rpc.AsyncResponder;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.messaging.ChannelSet;

// Define a ChannelSet object.
      public var cs:ChannelSet;

      // Define an AsyncToken object.
      public var token:AsyncToken;

      // Initialize ChannelSet object based on the
      // destination of the RemoteObject component.
      private function init():void {
        if (cs == null)
          cs = ServerConfig.getChannelSet(remoteObject.destination);
      }

// Login and handle authentication success or failure.
private function ROLogin():void {
  // Make sure that the user is not already logged in.
        if (cs.authenticated == false) {
          token = cs.login("alex", "password");
    // Add result and fault handlers.
    token.addResponder(new AsyncResponder(LoginResultEvent, LoginFaultEvent));
  }
}

      // Handle successful login.
      private function LoginResultEvent(event:ResultEvent, token:Object=null):void {
        switch(event.result) {
          case "success":
            authenticatedCB.selected = true;
          default:
        }
      }

      // Handle login failure.
      private function LoginFaultEvent(event:FaultEvent, token:Object=null):void {
        switch(event.fault.faultCode) {
          case "Client.Authentication":
          default:
            authenticatedCB.selected = false;
        }
      }

      // Logout and handle success or failure.
      private function ROLogout():void {
        // Add result and fault handlers.
        token = cs.logout();
        token.addResponder(new AsyncResponder(LogoutResultEvent,LogoutFaultEvent));
      }

      // Handle successful logout.
      private function LogoutResultEvent(event:ResultEvent, token:Object=null):void {
        switch (event.result) {
          case "success":
            authenticatedCB.selected = false;
          default:
        }
      }

      // Handle logout failure.
      private function LogoutFaultEvent(event:FaultEvent, token:Object=null):void {
        Alert.show("Logout failure: " + event.fault.faultString);
      }

      // Handle message recevied by RemoteObject component.
      private function resultHandler(event:ResultEvent):void {
        ta.text += "Congratulations! You've got server response: "+ event.result + "\n";
      }

      // Handle fault from RemoteObject component.
      private function faultHandler(event:FaultEvent):void {
        ta.text += "Oops! Something wrong: " + event.fault + "\n";
      }
  ]]>
  </mx:Script>

  <mx:HBox height="45">
    <mx:Button label="Login" click="ROLogin()"/>
    <mx:Button label="What roles do I have?" enabled="{authenticatedCB.selected}"
               click="remoteObject.allowedAuthorities()"/>
    <mx:Button label="Logout" click="ROLogout()"/>
    <mx:CheckBox id="authenticatedCB" label="Authenticated?" enabled="true"/>
  </mx:HBox>

  <mx:TextArea id="ta" width="100%" height="511"/>
  <mx:RemoteObject id="remoteObject"
   destination="hello"
   result="resultHandler(event)"
   fault="faultHandler(event)"/>

</mx:Application>

The end-----------------------------------
   发表时间:2009-02-26  
很好很详细,对我挺有帮助。

建议前面加个代码文件列表,思路概要,代码部分使用codestyle方便阅读。
0 请登录后投票
论坛首页 编程语言技术版

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