Obtener el nombre de usuario de inicio de sesión en java

92

¿Cómo puedo obtener el nombre de usuario / nombre de inicio de sesión en Java?

Este es el código que he probado ...

try{
    LoginContext lc = new LoginContext(appName,new TextCallbackHandler());
    lc.login();
    Subject subject = lc.getSubject();
    Principal principals[] = (Principal[])subject.getPrincipals().toArray(new Principal[0]);

    for (int i=0; i<principals.length; i++) {
        if (principals[i] instanceof NTUserPrincipal || principals[i] instanceof UnixPrincipal) {
            String loggedInUserName = principals[i].getName();
        }
    }

}
catch(SecurityException se){
    System.out.println("SecurityException: " + se.getMessage());
}

Me sale un SecurityExceptioncuando intento ejecutar este código. ¿Podría alguien decirme si voy en la dirección correcta y ayudarme a comprender el problema?

George Profenza
fuente
3
Tengo miedo de malinterpretarlo, pero no comprendo su pregunta. ¿Qué nombre de usuario de inicio de sesión? ¿Iniciar sesión en Windows / GNU Linux? ¿Autenticación básica en un servidor web?
guerda
Es imposible entender nada cuando no se publican detalles
matt b
Lo siento chicos. Soy nuevo en Java y ahora es un poco difícil de entender.
George Profenza

Respuestas:

224
System.getProperty("user.name")
dfa
fuente
4
+1 puede imprimir System.properties para obtener mucha información con la que se inicializa la VM
Markus Lausberg
3
Para mí, esto imprime el nombre del usuario que ejecuta la VM. No es el usuario que inició sesión en la aplicación Java.
Tom Brito
1
¿Está esto definido en alguna parte de una biblioteca de terceros ampliamente disponible? ¿O hay una constante definida en cualquier lugar de las clases proporcionadas por JDK para el user.namenombre de la propiedad?
Jeff Evans
29

en Unix:

new com.sun.security.auth.module.UnixSystem().getUsername()

en Windows:

new com.sun.security.auth.module.NTSystem().getName()

en Solaris:

new com.sun.security.auth.module.SolarisSystem().getUsername()
newacct
fuente
49
Este código va en contra de la filosofía de Java de escribir una vez, ejecutarse en cualquier lugar (introducción de código específico del sistema operativo) y, en segundo lugar, crea una dependencia en la implementación de Java de Sun.
Jin Kim
14
Intentar obtener el nombre de usuario es, por definición, específico de la plataforma. Es posible que una JVM que se ejecuta en un sistema de un solo usuario no tenga ningún nombre de usuario.
Chinmay Kanchi
8
@ChinmayKanchi: Si no hay un nombre de usuario, entonces la user.namepropiedad debería ser nula. Estoy de acuerdo con @JinKim, no escribas cosas que dependan del sistema operativo.
LS
2
user.name se puede configurar en la línea de comandos, por lo que depende en gran medida de cuál sea el caso de uso
Alice Purcell
3
Las clases de los paquetes com.sun no deben ser utilizadas por un desarrollador. Son internos y pueden cambiar en el futuro.
CHiRo79
17

inspirado en la respuesta de @newacct , un código que se puede compilar en cualquier plataforma:

String osName = System.getProperty( "os.name" ).toLowerCase();
String className = null;
String methodName = "getUsername";

if( osName.contains( "windows" ) ){
    className = "com.sun.security.auth.module.NTSystem";
    methodName = "getName";
}
else if( osName.contains( "linux" ) ){
    className = "com.sun.security.auth.module.UnixSystem";
}
else if( osName.contains( "solaris" ) || osName.contains( "sunos" ) ){
    className = "com.sun.security.auth.module.SolarisSystem";
}

if( className != null ){
    Class<?> c = Class.forName( className );
    Method method = c.getDeclaredMethod( methodName );
    Object o = c.newInstance();
    System.out.println( method.invoke( o ) );
}
celsowm
fuente
Buen uso de la reflexión :)
Zizouz212
5
Esto se romperá en Windows ya que el método en NTSystem para obtener el nombre de usuario es "getName ()" y no "getUsername ()". Supongo que puede hacer una verificación adicional y luego invocar el método correcto. ¿Es extraño que el JRE no lo abstraiga en un mecanismo independiente del sistema operativo?
John Mark Scarborough
1
Las com.sunclases no son accesibles de forma predeterminada en Java 9+. Esta solución no funcionará.
Thunderforge
A menos que se agregue una nueva API, creo que lo único que funcionará en Java 9 sería la solución de dfa .
Thunderforge
15

System.getProperty ("user.name") no es una buena opción de seguridad ya que esa variable de entorno podría ser falsificada: C: \ set USERNAME = "Joe Doe" java ... // le dará System.getProperty ("user. name ") Deberías hacer:

com.sun.security.auth.module.NTSystem NTSystem = new com.sun.security.auth.module.NTSystem();
System.out.println(NTSystem.getName());

JDK 1.5 y superior.

Lo uso dentro de un subprograma y tiene que estar firmado. fuente de información

pdjota
fuente
4
Esta no es una solución completa, ya que solo funciona en Windows.
LS
1
¿Esto también podría ser falsificado, por ejemplo, con un cargador de clases personalizado o una implementación personalizada de un com.sun.security.auth.module.NYSystemnivel superior en la ruta de clases? No sé si el tiempo de ejecución de Java intenta prevenir tales exploits, pero no creo que haya ninguna forma infalible de hacerlo 'seguro' excepto ejecutando código en una caja que es inaccesible para el cliente potencialmente malicioso. .
bacar
4
Me las arreglé para reemplazar con éxito la implementación de NTSystem.getName () usando PowerMock (que creo que usa un cargador de clases personalizado), por lo que realmente no puede confiar en algo como esto para la 'seguridad' ... sin embargo, no sé cómo están las cosas en el mundo de los applets. Pensé que si alguien puede proporcionar propiedades personalizadas del sistema, también puede proporcionar clases personalizadas o cargadores de clases personalizados.
bacar
1
-1 Porque solo funciona en Windows. NO deberías usar esto.
stommestack
@bacar: Estoy de acuerdo, que uno no debería confiar en esto y pensar que es bastante seguro. Pero en mi opinión, la seguridad se trata de "niveles". Y es mucho más fácil cambiar la variable de entorno que simular un método. En una empresa que no es de TI que usa NTSystem en lugar de la variable de entorno, se reduce a más de la mitad la cantidad de personas que pueden lograrlo: P. Por lo tanto, obtiene un poco más de seguridad, pero a su vez pierde algunas convenciones de Java en el camino.
Calon
6

Usar JNA es simple:

String username = Advapi32Util.getUserName();
System.out.println(username);

Advapi32Util.Account account = Advapi32Util.getAccountByName(username);
System.out.println(account.accountType);
System.out.println(account.domain);
System.out.println(account.fqn);
System.out.println(account.name);
System.out.println(account.sidString);

https://github.com/java-native-access/jna

ANTARA
fuente
1
Esto no funciona si ha iniciado sesión como usuario de dominio, pero también hay un usuario local con el mismo nombre. getAccountByName devolverá información para el usuario local.
Dave
2

El 'set Username = "Username"' es una anulación temporal que solo existe mientras las ventanas de cmd aún estén activas, una vez que se elimina, la variable pierde valor. Entonces creo que el

System.getProperty ("nombre.usuario");

sigue siendo un código breve y preciso de utilizar.

Newtoxton
fuente
1

System.getenv().get("USERNAME"); - ¡Funciona en Windows!

En las propiedades del entorno, tiene la información que necesita sobre la computadora y el host. ¡Lo digo de nuevo! ¡Funciona en WINDOWS!

Dragos Roban
fuente
¿Qué hay de System.getenv("username")? :)
RUMANIA_engineer
El trabajo de Doens si la máquina virtual, digamos tomcat, se inicia como un servicio de Windows, devuelve algo que incluye el nombre de host
Deepak
0

A continuación se muestra una solución SOLO para WINDOWS

En los casos en que la aplicación (como Tomcat) se inicia como un servicio de Windows, System.getProperty ("user.name") o System.getenv (). Get ("USERNAME") devuelven el usuario que inició el servicio y no el actual nombre de usuario registrado.

También en Java 9, las clases NTSystem, etc.no serán accesibles

Entonces, solución para Windows: puede usar wmic , por lo que debe ejecutar el siguiente comando

wmic ComputerSystem get UserName

Si está disponible, esto devolverá la salida del formulario:

UserName
{domain}\{logged-in-user-name}

Nota: Para Windows, debe usar cmd / c como prefijo, por lo que a continuación se muestra un programa básico como ejemplo:

    Process exec = Runtime.getRuntime().exec("cmd /c wmic ComputerSystem get UserName".split(" "));
    System.out.println(exec.waitFor());
    try (BufferedReader bw = new BufferedReader(new InputStreamReader(exec.getInputStream()))) {
        System.out.println(bw.readLine() + "\n" + bw.readLine()+ "\n" + bw.readLine());
    }
Deepak
fuente