2011-05-27 12 views
17

Tengo una aplicación web Java que tiene un sitio web para las interacciones del usuario. Para autenticar a los usuarios, configuré la aplicación a través de web.xml para utilizar la autenticación basada en formularios. Los usuarios se reenvían a una página de inicio de sesión y todo está bien hasta el momento.Multiple login-config para Java webapp

Ahora estamos desarrollando un cliente de escritorio (en C#) para esta aplicación web que accede a la aplicación a través de servicios web RESTful. Implementé estos servicios en la misma aplicación web que el sitio web y, por supuesto, la persona que llama del servicio web también debe ser autenticada. Pero ahora estoy enfrentando el problema, que cada vez que llamo a un servicio web, el servidor devuelve el HTML de la página de inicio de sesión como respuesta.

Creo que sería genial poder utilizar otro login-config para mi servlet de servicio REST (que probablemente usaría la autenticación BASIC).

Google no mencionó mucho, pero no puedo creer que sea el primero en estar en tal situación. Entonces me gustaría escuchar sus pensamientos y soluciones.

Cualquier sugerencia es apreciada.

Respuesta

5

La única solución es tener dos aplicaciones para dos clientes con diferentes mecanismos de inicio de sesión. El código de la aplicación debe separarse y moverlo a la aplicación común a la que estas aplicaciones envían las solicitudes.

De lo contrario, use su autenticación personalizada.

+0

Thank you. Ya pensé que esto no sería posible. Así que creo que la mejor opción es implementar una autenticación personalizada para los servicios web ... – hage

1

Desafortunadamente, login-config no está correlacionado como los filtros y los servlets, por lo que solo hay un global para la aplicación web. Eso significa que o necesita 2 webapps o si está en JBoss, puede usar la clase WebAuthentication para informar al contenedor sobre el inicio de sesión programático de su aplicación. Sin embargo, si está utilizando embarcadero embebido u otros servidores web, no hay manera de apoyar BASIC y FORM juntos utilizando web.xml. Tendría que escribir un servicio de autenticación personalizado

Sin embargo, puede convertir a Apache Shiro y resolverá estos problemas en un diseño sorprendentemente bien escrito y simple. Estos pasos permitirán a los clientes de REST usar la autenticación BÁSICA en cada página sin una cookie de sesión o iniciar sesión en/rest/login y recibir una sesión. Los clientes del navegador pueden usar FORM auth

1) protect /login with "authc", set shiro.loginUrl to /login and host an HTML form at that location 
2) protect /rest/login with "anon" and write a URL handler for POST with this code 
    UsernamePasswordToken token = new UsernamePasswordToken(userName, password); 
    token.setRememberMe(rememberMe); 
    SecurityUtils.getSubject().login(token); 
3) protect /rest/logout with "logout" 
4) protect /rest/** with "noSessionCreation, authcBasic, rest" 
3

He resuelto este problema con una válvula tomcat. La válvula comprueba la presencia de un encabezado de Autorización, en cuyo caso, el encabezado se utiliza como credenciales para autenticar al usuario; de lo contrario, tiene lugar el método de autenticación normal.

Este es el código de la válvula:

package org.tastefuljava.tomcat; 

import java.io.IOException; 
import java.security.Principal; 
import javax.servlet.ServletException; 
import org.apache.catalina.Realm; 
import org.apache.catalina.connector.Request; 
import org.apache.catalina.connector.Response; 
import org.apache.catalina.valves.ValveBase; 

public class AutoBasicValve extends ValveBase { 
    private static final String BASIC_PREFIX = "basic "; 

    private String encoding = "UTF-8"; 

    public String getEncoding() { 
     return encoding; 
    } 

    public void setEncoding(String encoding) { 
     this.encoding = encoding; 
    } 

    @Override 
    public void invoke(Request request, Response response) 
      throws IOException, ServletException { 
     Principal principal = request.getUserPrincipal(); 
     Realm realm = getContainer().getRealm(); 
     if (principal != null) { 
      if (containerLog.isDebugEnabled()) { 
       containerLog.debug(
         "Already authenticated as: " + principal.getName()); 
      } 
     } else if (realm == null) { 
      if (containerLog.isDebugEnabled()) { 
       containerLog.debug("No realm configured"); 
      } 
     } else { 
      String auth = request.getHeader("authorization"); 
      if (auth != null) { 
       if (auth.toLowerCase().startsWith(BASIC_PREFIX)) { 
        auth = auth.substring(BASIC_PREFIX.length()); 
        byte[] bytes = Base64.decode(auth); 
        auth = new String(bytes, encoding); 
        int ix = auth.indexOf(':'); 
        if (ix >= 0) { 
         String username = auth.substring(0, ix); 
         String password = auth.substring(ix+1); 
         principal = realm.authenticate(username, password); 
         if (principal == null) { 
          containerLog.warn(
            "Could not authenticate " + username); 
         } else { 
          containerLog.info(
            "Authenticated as " + principal.getName()); 
          request.setAuthType("BASIC"); 
          request.setUserPrincipal(principal); 
         } 
        } 
       } 
      } 
     } 
     getNext().invoke(request, response); 
    } 
} 

Puede utilizar la válvula mediante la adición de una etiqueta > < la válvula, ya sea en el archivo server.xml en la instalación de Tomcat, o en el META-INF/contexto.archivo XML de su aplicación web:

El proyecto se encuentra en github: https://github.com/robbyn/mydsrealm

+0

Guau, genial. Si aún fuera 2011, podría usarlo :) ¡Pero gracias por tu trabajo! Espero que esto ayude a alguien. ¿Ahora si hay algo similar para Glassfish? – hage

+0

Lo siento, no sé –