Kategorie: Spring

GAE/J und Spring: Teil 3

Spring Security und GAE/J

Da die normale Spring-Security.jar nur semi-compatible ist, laden wir uns eine modifizierte Version hier herunter:Download

Diese kommt dann statt der spring-security.jar in unseren Classpath.

Danach wird die “Filterkette” von Spring in der web.xml konfiguriert und die application-security-context.xml eingebunden:

	
contextConfigLocation

			WEB-INF/application-context.xml
			WEB-INF/application-security-context.xml
			
	
	
  		springSecurityFilterChain
  		org.springframework.web.filter.DelegatingFilterProxy
	

	
  		springSecurityFilterChain
  		/*
	

Da wir unseren UserDetailsService, sowie unsere UserDetails und GrantedAuthority selber schreiben müssen, mußte ich ein etwas größeres Refactoring machen. Ich werde aber, wenn alles fertig ist, die App im SVN öffentlich machen, so das sich jeder die Sourcen downloaden kann.

Als nächstes wird die application-security-context.xml konfiguriert:
(Diese ist schon für später etwas umfangreicher geworden, aber ich denke, man findet sich trotzdem noch gut zurecht)

 

 	
 		
 		
 		

 	

 	
		
			
		
	

	

 	

 	

 	 


	 

 	

  	


  		

 	


Als nächstes schreiben wir uns unseren UserDetailsService und unsere GrantedAuthority:

public class GAEGrantedAuthority implements GrantedAuthority
{

	public static final String ROLE_USER 	= "ROLE_USER";
	public static final String ROLE_ADMIN 	= "ROLE_ADMIN";

	@PrimaryKey
	@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
	private Key key;

	@Persistent
	private String role;

	@Override
	public String getAuthority()
	{
		return role;
	}

	@Override
	public int compareTo(Object o)
	{
		if (o != null && o instanceof GrantedAuthority)
		{
			GrantedAuthority rhs = (GrantedAuthority) o;
			return this.role.compareTo(rhs.getAuthority());
		}
		return -1;
	}
//getter/setter
}
public class GAEUserdetailsService implements UserDetailsService
{
	private UserDAO userDAO;

	@Override
	public UserDetails loadUserByUsername(String arg0)
			throws UsernameNotFoundException, DataAccessException
	{
		UserDetails userDetails = userDAO.findUserByUsername(arg0);
		if(null == userDetails)
			throw new UsernameNotFoundException("Invalid User Credentials");

		return userDetails;
	}

	public void setUserDAO(UserDAO userDAO)
	{
		this.userDAO = userDAO;
	}

}

Anschließend implementiert der User noch die UserDetails:

@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class User implements UserDetails
{
	@PrimaryKey
	@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
	private Key key;

	@Persistent
	private String password;

	@Persistent
	private String username;

	@Persistent
	private boolean enabled;

	@Persistent
	private boolean accountNonLocked;

	@Persistent
	private boolean credentialsNonExpired;

	@Persistent
	private boolean accountNonExpired;

	@Persistent(defaultFetchGroup = "true")
	private List grantedAuthorities = Lists.newArrayList();

	@Persistent
	private String email;

	@Persistent
	private BigDecimal weight;

	@Persistent
	private BigDecimal desiredWeight;

	@Persistent(mappedBy = "user",defaultFetchGroup = "true")
	private List weightUnits  = Lists.newArrayList();

	@Override
	public GrantedAuthority[] getAuthorities()
	{
		return (GrantedAuthority[]) grantedAuthorities.toArray(new GrantedAuthority[]{});
	}
//getter,setter...
}

Die in der application-security.xml eingetragenen MyAuthenticationProcessingFilter und MyAuthenticationEntryPoint kann man vorerst leer implementieren und verdrahten …

Natürlich müssen jetzt noch Controller und JSPs für den “sicheren Bereich” angelegt werden, aber das sollte ja kein Problem sein.

Interessanterweise funktioniert alles, wenn ich die App auf meinem Rechner deploye, jedoch fliegen in der Cloud noch Exceptions!
Dies liegt daran, das Strings einen StringTrimmerEditor benötigen! Entweder registriert jeder Controller seinen eigenen CustomEditor oder man registriert global einen Editor für alle Strings. Ich habe gelesen, das man besser auch sämtliche Variablen, die das BackingObject im View benutzt, lieber nicht als primitive Datentypen anlegt!

Inzwischen läuft alles schon testmäßig in der Cloud unter Link

Falls einer Lust & Zeit hat, Oberflächen zu designen, kann er sich ja mal melden!

Als nächstes werde ich die Eingabeoberflächen programmieren (darauf gehe ich aber nicht ein) und ich werde versuchen, irgendewas ähnlich JFreeChart oder so einzubinden, damit ich Verlaufsgrafiken darstellen kann. Außerdem versuche ich, Springs MailSender einzubinden…



GAE/J und Spring: Teil 1

Aufsetzen eines GAE/J-Projekts

Download und Installation des Google App Engine SDK: SDK
Außerdem natürlich das Plugin für Eclipse: Plugin

Dann ein neues Web Application Project anlegen, dabei aber den Haken bei “Use Google Web Toolkit” rausnehmen
Anlegen

Als nächstes die Spring Libraries hinzufügen:

  • spring-core.jar
  • spring-beans.jar
  • spring-context.jar
  • spring-web.jar
  • spring-webmvc.jar
  • jstl.jar
  • standard.jar
  • commons-logging.jar

Auf keinen Fall die All-In-One spring.jar benutzen, da javax.naming.* von GAE nicht unterstützt wird.

Spring Security lasse ich vorerst weg!

Als nächstes in der web.xml das Dispatcher-Servlet bekanntmachen:



	
		dispatcher
		org.springframework.web.servlet.DispatcherServlet
		1
	

	
		dispatcher
		*.html
	

	

org.springframework.web.context.ContextLoaderListener
	
	
contextConfigLocation

			WEB-INF/application-context.xml
			
	

    
    	index.jsp
    

Achtung: Wer El/JSTL benutzen möchte, sollte die 2.4 Version im Schema verwenden, oder ElIgnored in der JSP auf false setzen!

Ich habe auch schon für später eine application-context.xml in der web.xml angelegt!

Eine JSP mit Formular, um sich anzumelden:

<%@ page language="java" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="/jsp/include.jsp"%>




Username
Passwort

Der dazugehörende Controller:

package de.pmannel.login;

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

import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;
import org.springframework.web.servlet.view.RedirectView;

public class LoginController extends SimpleFormController
{

	@Override
	protected ModelAndView onSubmit(HttpServletRequest request,
			HttpServletResponse response, Object command, BindException errors)
			throws Exception
	{
		ModelAndView mv = new ModelAndView(new RedirectView(getSuccessView()));

		User user = (User)command;
		mv.addObject("username",user.getJ_username());
		return mv;
	}
}

Die Jsp, an die gepostet wird:

<%@ page language="java" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="/jsp/include.jsp"%>

hi !

Der Controller dafür:

package de.pmannel.login;

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

import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

public class MyAppController implements Controller
{

	@Override
	public ModelAndView handleRequest(HttpServletRequest arg0,
			HttpServletResponse arg1) throws Exception
	{
		ModelAndView mv = new ModelAndView("myapp");

		mv.addObject("username",ServletRequestUtils.getStringParameter(arg0, "username"));

		return mv;
	}
}

und meine Dispatcher-Servlet.xml:



	




loginController
myAppController
		
		
	

	




	

	

	


	


in der include.jsp kommen folgende Taglibs:

<%@ taglib prefix="c" 			uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" 		uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="spring" 		uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="form" 		uri="http://www.springframework.org/tags/form" %>

Wenn dann alles soweit fertig ist, rechte Maustaste auf das Projekt, Run As –> Web Application!

Damit läuft GAE/J schonmal mit Spring MVC! Als nächstes versuche ich, mit Spring ORM und JDO den User im DataStore zu speichern.