Integracja Shiro, Guice i GWT

Jako że w związku z nadchodzącym dłuższym weekendem majowym (ręce do góry, kto nie bierze urlopu?), nastroje dziś są mocno weekendowe, będzie szybko i przyjemnie :) Poprzednio opisywałem w jaki sposób użyć Shiro w aplikacji GWT. Obecna wtedy wersja Shiro (1.1.0) nie wspierała natywnie Guice‚a, dlatego konfigurację oparliśmy na standardowych plikach shiro.ini oraz web.xml. Oczywiście wersję 1.1.0 da się zintegrować z Guice’m, co wymaga jednak użycia kilku tricków. Jeśli jesteś zainteresowany właśnie tą wersją Shiro, to w sieci można znaleźć kilka dobrych poradników.

Od jakiegoś czasu Shiro dostępne jest w wersji 1.2.0, w której to Guice jest już oficjalnie wspierany. Niestety na oficjalnej stronie Shiro nie wszystko zostało dokładnie wytłumaczone, dlatego chcę zaprezentować Ci najprostszy sposób połączenia tych dwóch framework’ów. Użyjemy do tego poprzednio stworzonej aplikacji, tak aby skupić się tylko na integracji z Guice’m.

GuiceShiroModule.java

public class GuiceShiroModule extends ShiroWebModule {

  public GuiceShiroModule(ServletContext servletContext) {
    super(servletContext);
  }

  @SuppressWarnings("unchecked")
  @Override
  protected void configureShiroWeb() {
    try {
      bindRealm().toConstructor(IniRealm.class.getConstructor(Ini.class));
    } catch (Exception e) {
      addError(e);
    }

    Key<GWTAuthenticationFilter> filter = Key.get(GWTAuthenticationFilter.class);

    addFilterChain("/login.html", ANON);
    addFilterChain("/favicon.ico", ANON);
    addFilterChain("/*", filter);
  }

  @Provides
  Ini loadShiroIni() {
    return Ini.fromResourcePath("classpath:shiro.ini");
  }
}

Mamy tu klasę modułu guicowego dla obsługi Shiro. Definiujemy tu domenę uwierzytelniania (IniRealm) opartą o pliki konfiguracyjny shiro.ini. Zawartość pliku jest dostarczana przez Guice’a za pomocą metody oznaczonej adnotacją @Provides. Warto tu zaznaczyć, że pomimo zbieżności nazw pliku konfiguracyjnego shiro.ini ze standardową konfiguracją Shiro, z pliku tego odczytywane są tylko informacje o użytkownikach i rolach.

W module zdefiniowany też został filtr GWTAuthenticationFilter, który będzie przekierowywał nas do strony logowania po wejściu na zastrzeżony zasób. Dodatkowo dodano tu reguły pozwalające na odczyt strony logowania dla anonimowego użytkownika.

GWTAuthenticationFilter.class

public class GWTAuthenticationFilter extends PassThruAuthenticationFilter {

  public static final String GWT_LOGIN_URL = "/login.html?gwt.codesvr=127.0.0.1:9997";

  public GWTAuthenticationFilter() {
    setLoginUrl(GWT_LOGIN_URL);
  }
}

W klasie tej zdefiniowany został adres strony logowania. Drobną bolączką jest to, że zaszyłem tu na sztywno parametr dla trybu deweloperskiego GWT, dlatego warto tu dorobić jakieś odczytywanie adresu strony logowania z osobnego pliku konfiguracyjnego.

GuiceServletConfig.java

public class GuiceServletConfig extends GuiceServletContextListener {

  private ServletContext servletContext;

  @Override
  public void contextInitialized(ServletContextEvent servletContextEvent) {
    servletContext = servletContextEvent.getServletContext();
    super.contextInitialized(servletContextEvent);
  }

  @Override
  protected Injector getInjector() {
    Injector injector = Guice.createInjector(
        new GuiceShiroModule(servletContext),
        ShiroWebModule.guiceFilterModule()
    );

    return injector;
  }
}

Jest to główny plik konfiguracyjny Guice’a, w którym tworzony jest obiekt Injector’a obsługującego zadeklarowane moduły guicowe. Jeden z modułów utworzony został przez nas wcześniej, a drugi to wewnętrzny moduł Shiro do obsługi aplikacji webowych, który jest odpowiednikiem definicji filtra ShiroFilter w pliku web.xml.

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

  <filter>
    <filter-name>GuiceFilter</filter-name>
    <filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
  </filter>

  <filter-mapping>
    <filter-name>GuiceFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

  <listener>
    <listener-class>pl.avd.samples.gwt.shiro.server.GuiceServletConfig</listener-class>
  </listener>

  (...)

</web-app>

W pliku deskryptora webowego web.xml należy umieścić definicję filtra Guice’a oraz listener wczytujący główną klasę konfiguracyjną Guice’a. Definicja filtru Shiro nie jest tu już oczywiście potrzebna.

shiro.ini

[users]
test1 = pass1,users
test2 = pass2,users

W pliku shiro.ini tak jak pisałem wcześniej, znajduje się tylko definicja użytkowników i ról oraz, rzecz jasna, haseł.

To tyle na dziś. Jak widać, integracja Shiro z Guice’m w projekcie GWT jest bardzo prosta, a warto z niej skorzystać przede wszystkim wtedy, gdy mamy własną domenę uwierzytelniania, w której chcemy korzystać z dobrodziejstw wstrzykiwania zależności, za które odpowiada Guice. Źródła projektu można pobrać z repozytorium.

Na koniec życzę Ci miłego majowego wypoczynku, podczas którego będziesz się trzymać jak najdalej tematów związanych z programowaniem :) – na to przyjdzie pora po powrocie z urlopu. A dla umilenia wypoczynku polecam dobre wino :)

Skomentuj


UWAGA - Możesz używać HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

CommentLuv badge