Получить логин на Java


92

Как я могу получить имя пользователя / имя для входа в Java?

Это код, который я пробовал ...

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());
}

Я получаю, SecurityExceptionкогда пытаюсь запустить этот код. Не мог бы кто-нибудь сказать мне, иду ли я в правильном направлении, и помочь мне разобраться в проблеме.


3
Боюсь вас неправильно понять, но я не понимаю вашего вопроса. Какое имя пользователя для входа? Вход в Windows / GNU Linux? Базовая аутентификация на веб-сервере?
guerda

Невозможно ничего понять, когда не публикуются подробности
matt b

Извините ребята. Я новичок в Java, и сейчас это немного сложно понять.
Джордж Профенца,

Ответы:


225
System.getProperty("user.name")

4
+1, вы можете распечатать System.properties, чтобы получить много информации, которой инициализируется виртуальная машина
Маркус Лаусберг

3
Для меня это печатает имя пользователя, запускающего виртуальную машину. Не авторизованный пользователь в java-приложении.
Tom Brito

1
Это определено где-нибудь в широко доступной сторонней библиотеке? Или есть константа, определенная где-нибудь в JDK-классах для имени user.nameсвойства?
Джефф Эванс,

29

в Unix:

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

в Windows:

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

в Solaris:

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

49
Этот код противоречит философии Java: писать один раз, запускать где угодно (введение кода, специфичного для ОС), а во-вторых, он создает зависимость от реализации Java от Sun.
Джин Ким

14
Попытка получить имя пользователя по определению зависит от платформы. JVM, работающая в однопользовательской системе, может вообще не иметь имени пользователя.
Chinmay Kanchi

8
@ChinmayKanchi: Если имя пользователя отсутствует, user.nameсвойство должно иметь значение null. Я согласен с @JinKim, не пишите вещи, зависящие от ОС.
Mr. Lance E Sloan

2
user.name может быть задано в командной строке, поэтому это очень сильно зависит от сценария использования
Alice Purcell

3
Классы из пакетов com.sun не должны использоваться разработчиком. Они внутренние и могут измениться в будущем.
CHiRo79

17

вдохновленный ответом @newacct , код, который можно скомпилировать на любой платформе:

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 ) );
}

Хорошее использование отражения :)
Zizouz212 08

5
Это не работает в Windows, поскольку в NTSystem для получения имени пользователя используется метод getName (), а не getUsername (). Я полагаю, вы можете провести дополнительную проверку, а затем вызвать правильный метод. Странно, но это не абстрагируется от независимого от ОС механизма JRE?
Джон Марк Скарборо,

1
Эти com.sunклассы не доступны по умолчанию в Java 9+. Это решение не подойдет.
Thunderforge

Если не будет добавлен какой-то новый API, я думаю, единственное, что будет работать в Java 9, - это решение dfa .
Thunderforge

15

System.getProperty ("user.name") не является хорошим вариантом безопасности, поскольку эта переменная среды может быть подделана: C: \ set USERNAME = "Joe Doe" java ... // предоставит вам System.getProperty ("user. name ") Вам следует сделать:

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

JDK 1.5 и выше.

Я использую его в апплете, и он должен быть подписан. источник информации


4
Это не полное решение, поскольку оно работает только под Windows.
Мистер Лэнс И Слоан,

1
Может ли это быть подделано, например, с помощью пользовательского загрузчика классов или пользовательской реализации com.sun.security.auth.module.NYSystemболее высокого уровня в пути к классам? Я не знаю, пытается ли среда выполнения Java предотвратить такие эксплойты, но я не думаю, что будет какой-либо ненадежный способ сделать его `` безопасным '', кроме запуска кода в поле, недоступном для потенциально вредоносного клиента. .
bacar

4
Мне только что удалось заменить реализацию NTSystem.getName () с помощью PowerMock (который, как мне кажется, использует собственный загрузчик классов), так что вы действительно не можете полагаться на что-то подобное для «безопасности» ... однако я не знаю как обстоят дела в мире апплетов. Я бы подумал, что если кто-то может предоставить настраиваемые системные свойства, он также может предоставить настраиваемые классы или настраиваемые загрузчики классов.
bacar

1
-1 Потому что работает только в Windows. Вы НЕ должны использовать это.
Stommestack

@bacar: Я согласен, что не стоит полагаться на это и думать, что это довольно безопасно. Но, на мой взгляд, безопасность - это «уровни». И изменить переменную среды намного проще, чем смоделировать метод. В компании, не связанной с ИТ, использование NTSystem вместо переменной среды более чем вдвое сокращает количество людей, которые могут это осуществить: P. Таким образом, вы получаете немного больше безопасности, но, в свою очередь, теряете некоторые Java-соглашения в дороге.
Calon

6

Используя JNA, это просто:

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


1
Это не работает, если вы вошли в систему как пользователь домена, но есть также локальный пользователь с таким же именем. getAccountByName вернет информацию для локального пользователя.
Дэйв

2

«Установлено Имя пользователя =„Имя пользователя“» временная коррекция , которая существует только до тех пор , пока CMD окна все еще вверх, как только он убит, переменная теряет значение. Так что я думаю

System.getProperty ("имя_пользователя");

по-прежнему короткий и точный код для использования.


1

System.getenv().get("USERNAME"); - работает на окнах!

В свойствах среды у вас есть необходимая информация о компьютере и хосте! Я еще раз говорю! Работает на WINDOWS!


О чем System.getenv("username")? :)
ROMANIA_engineer 06

Работа Doens, если виртуальная машина - скажем, tomcat - запущена как служба Windows, она возвращает что-то, включающее имя хоста,
Дипак,

0

Ниже приведено решение ТОЛЬКО для WINDOWS

В случаях, когда приложение (например, Tomcat) запускается как служба Windows, System.getProperty ("user.name") или System.getenv (). Get ("USERNAME") возвращают пользователя, запустившего службу, а не имя текущего авторизованного пользователя.

Также в Java 9 классы NTSystem и т. Д. Не будут доступны

Итак, обходной путь для Windows: вы можете использовать wmic , поэтому вам нужно выполнить следующую команду

wmic ComputerSystem get UserName

Если доступно, это вернет вывод формы:

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

Примечание: для окон вам нужно использовать cmd / c в качестве префикса, поэтому ниже в качестве примера представлена ​​грубая программа:

    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());
    }
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.