Kategorie: Google App Engine

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 2

Speichern von Daten per JDO

Als erstes werde ich mal die Domainenobjekte anlegen, in diesem Fall erstmal einen User und als 1:N die dazugehörigen WeightUnits, bestehend aus Gewicht/Tag. Außerdem benötigen wir noch die DAOs/Services sowie die PersistenceManagerFactory:

Für die Transaktionen muss noch die spring-tx.jar, spring-aop.jar und aopalliance-1.0.jar zum Classpath zugefügt werden.

Hier der User:

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

	@Persistent
	private String j_username;

	@Persistent
	private String j_password;

	@Persistent
	private String email;

	@Persistent
	private BigDecimal weight;

	@Persistent
	private BigDecimal desiredWeight;

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

//getter/setter
}

Und die WeightUnit:

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

	@Persistent
	private Date day;

	@Persistent
	private BigDecimal weight;

	@Persistent
	private User user;

//getter/setter

}

In der application-context.xml wird die PersistenceManagerFactory verdrahtet:


	

 	

 	

 	

 	

 	

 	

 	

anschließend benötigen wir die DAOs zum Speichern und Auslesen. Zu jeder DAOImpl gehört natürlich ein Interface, welches ich aus Platzgründen weg lasse:

public class UserDAOImpl extends JdoDaoSupport implements UserDAO
{

	@Override
	public void delete(User user)
	{
		// TODO Auto-generated method stub

	}

	@Override
	public User findUserById( Key key)
	{
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public User save(User user)
	{
			return getPersistenceManager().makePersistent(user);
	}

}

Ich verwende hier den JdoDaoSupport und binde mich damit an Spring, wer möchte kann sich die Factory auch selber injecten.

Anschließend noch Service/ServiceImpl erzeugen und in einen Controller injecten.

Damit die Session während eines Views nicht geschlossen werden, kommt noch ein OpenPersistenceInViewFilter in die web.xml.



	OpenPersistenceManagerInViewFilter
	org.springframework.orm.jdo.support.OpenPersistenceManagerInViewFilter


	OpenPersistenceManagerInViewFilter
	/*


Im nächsten Teil versuche ich dann, Spring Security in der Anwendung zum Laufen zu bekommen.