Verificando se um logon do SQL Server já existe

176

Preciso verificar se já existe um logon específico no SQL Server e, se não existir, preciso adicioná-lo.

Encontrei o código a seguir para realmente adicionar o logon ao banco de dados, mas quero agrupá-lo em uma instrução SE (de alguma forma) para verificar se o logon existe primeiro.

CREATE LOGIN [myUsername] WITH PASSWORD=N'myPassword', 
DEFAULT_LANGUAGE=[us_english], 
CHECK_EXPIRATION=OFF, 
CHECK_POLICY=OFF 
GO

Entendo que preciso interrogar um banco de dados do sistema, mas não sei por onde começar!

Brett Rigby
fonte
10
Essa é uma pergunta importante, mas, como foi formulada, parece não ter uma distinção importante: usuário x login. O potencial duplicado ao qual Jon se vinculou realmente parece ser sobre os usuários. Esta pergunta diz "usuário" no título, mas lida com logins no código da pergunta e na resposta aceita. Eu editei o título e a pergunta de acordo.
LarsH
1
Apenas para adicionar ao comentário por @LarsH, os logins são associados a uma instância do servidor SQL e os usuários são associados a um banco de dados específico. Os usuários do banco de dados podem ser criados a partir de logons do servidor, para que eles tenham acesso a um banco de dados específico. Veja este excelente artigo e na verdade toda a série faz parte da (stariway a segurança do SQL Server)
Engenheiro invertida

Respostas:

141

A partir daqui

If not Exists (select loginname from master.dbo.syslogins 
    where name = @loginName and dbname = 'PUBS')
Begin
    Select @SqlStatement = 'CREATE LOGIN ' + QUOTENAME(@loginName) + ' 
    FROM WINDOWS WITH DEFAULT_DATABASE=[PUBS], DEFAULT_LANGUAGE=[us_english]')

    EXEC sp_executesql @SqlStatement
End
Johnno Nolan
fonte
6
você deve usar QUOTENAME para evitar a injeção de sql. O atacante pode passar um @loginName como #x] with password ''y'';\r\ndrop table foo;\r\n
Remus Rusanu
2
Por que foi necessário criar uma instrução como uma string e usar sp_executesql, em vez de apenas entrar diretamente CREATE LOGIN [@loginName] FROM ...? Pardon minha ignorância, eu gostaria de saber ...
Larsh
4
@LarsH: é necessário criar a instrução como uma string porque CREATE LOGIN não pode usar um parâmetro para o nome de login, requer uma literal de string. Não sei por que, mas descobri da maneira mais difícil que é verdade.
Joseph Bongaarts 29/04
@JosephBongaarts: OK, obrigado. Eu acho que é como nomes de tabela nas instruções SELECT. Talvez a idéia seja diminuir a área de superfície vulnerável a ataques, embora eu não saiba que isso ajudaria.
LarsH
1
Eu acho que QUOTENAME()circula @loginName, não toda a declaração, e então você pode se livrar dos delimitadores manuais e manuais @loginName.
Brianary
288

Aqui está uma maneira de fazer isso no SQL Server 2005 e versões posteriores sem usar a exibição syslogins descontinuada:

IF NOT EXISTS 
    (SELECT name  
     FROM master.sys.server_principals
     WHERE name = 'LoginName')
BEGIN
    CREATE LOGIN [LoginName] WITH PASSWORD = N'password'
END

A visualização server_principals é usada em vez de sql_logins porque o último não lista os logins do Windows.

Se você precisar verificar a existência de um usuário em um banco de dados específico antes de criá-los, poderá fazer o seguinte:

USE your_db_name

IF NOT EXISTS
    (SELECT name
     FROM sys.database_principals
     WHERE name = 'Bob')
BEGIN
    CREATE USER [Bob] FOR LOGIN [Bob] 
END
Derek Morrison
fonte
17
Melhor resposta, sem sql dinâmico envolvido, nem uso de exibição obsoleta. Obrigado!
Casper Leon Nielsen
7
No caso do SQL Azure, as duas tabelas de destino são sys.sql_logins e sys.sysusers - pode ser bom incluir isso na resposta.
18716 Brett
Não é útil se o seu script precisar usar um nome de usuário variável.
Ross Presser
@Derek Morrison, podemos adicionar mais uma condição para o SID
AstroBoy
30

Como uma adição menor a esse segmento, em geral você deseja evitar o uso dos modos de exibição que começam com sys.sys *, pois a Microsoft os inclui apenas para compatibilidade com versões anteriores. Para o seu código, você provavelmente deve usar sys.server_principals. Isso pressupõe que você esteja usando o SQL 2005 ou superior.

Bomlin
fonte
Testado, funciona e mais atual que as outras respostas. +1 para você também.
David
Sim, em 2005 a Microsoft retirou o acesso direto às tabelas do sistema. Para não quebrar o código antigo, eles incluem exibições com o mesmo nome das tabelas antigas. No entanto, eles destinam-se apenas ao código mais antigo e o código mais recente deve usar os novos modos de exibição. No BOL, faça uma pesquisa nas tabelas do sistema de mapeamento para descobrir o que você deve usar.
Bomlin 04/04/09
11

Você pode usar a função interna:

SUSER_ID ( [ 'myUsername' ] )

através da

IF [value] IS NULL [statement]

gostar:

IF SUSER_ID (N'myUsername') IS NULL
CREATE LOGIN [myUsername] WITH PASSWORD=N'myPassword', 
DEFAULT_LANGUAGE=[us_english], 
CHECK_EXPIRATION=OFF, 
CHECK_POLICY=OFF 
GO

https://technet.microsoft.com/en-us/library/ms176042(v=sql.110).aspx

Hüda
fonte
Voto positivo para inclusão de campos opcionais que desabilitam as verificações de política e expiração.
Archibald
8

Tente isto (substitua 'user' pelo nome de login real):

IF NOT EXISTS(
SELECT name 
FROM [master].[sys].[syslogins]
WHERE NAME = 'user')

BEGIN 
    --create login here
END
Marc
fonte
@ Marc: Desculpe, mas você está errado. A tabela [syslogins] mantém logins e a tabela [sysusers] mantém os usuários.
22410 abatishchev
6

Isso funciona no SQL Server 2000.

use master
select count(*) From sysxlogins WHERE NAME = 'myUsername'

no SQL 2005, altere a segunda linha para

select count(*) From syslogins WHERE NAME = 'myUsername'

Não tenho certeza sobre o SQL 2008, mas acho que será o mesmo que o SQL 2005 e, se não, isso deve lhe dar uma idéia de onde começar a procurar.

David
fonte
5

o que você exatamente deseja verificar para logon ou usuário? um login é criado no nível do servidor e um usuário é criado no nível do banco de dados para que um login seja exclusivo no servidor

Além disso, um usuário é criado contra um logon, um usuário sem logon é um usuário órfão e não é útil, pois você não pode executar o logon do servidor sql sem um logon

talvez você precise disso

verifique o login

select 'X' from master.dbo.syslogins where loginname=<username>

a consulta acima retornará 'X' se o login existir, senão retornará nulo

então crie um login

CREATE LOGIN <username> with PASSWORD=<password>

isso cria um logon no servidor sql. mas aceita apenas senhas fortes

crie um usuário em cada banco de dados que você deseja fazer login como

CREATE USER <username> for login <username>

atribuir direitos de execução ao usuário

 GRANT EXECUTE TO <username>

É necessário ter permissões SYSADMIN ou dizer 'sa' para abreviar

você pode escrever um procedimento sql para isso em um banco de dados

create proc createuser
(
@username varchar(50),
@password varchar(50)
)
as
begin
if not exists(select 'X' from master.dbo.syslogins where loginname=@username)
begin
 if not exists(select 'X' from sysusers where name=@username)
 begin
exec('CREATE LOGIN '+@username+' WITH PASSWORD='''+@password+'''')
exec('CREATE USER '+@username+' FOR LOGIN '+@username)
exec('GRANT EXECUTE TO '+@username)
end
end
end
Akshita
fonte
5

Para lidar com conflitos de nomenclatura entre logins, funções, usuários etc., verifique a typecoluna de acordo com a documentação do Microsoft sys.database_principals

Para lidar com chacters especiais em nomes de usuário, etc, use N'<name>'e de [<name>]acordo.

Criar login

USE MASTER
IF NOT EXISTS (SELECT 1 FROM master.sys.server_principals WHERE 
[name] = N'<loginname>' and [type] IN ('C','E', 'G', 'K', 'S', 'U'))
    CREATE LOGIN [<loginname>] <further parameters>

Criar usuário do banco de dados

USE <databasename>
IF NOT EXISTS (SELECT 1 FROM sys.database_principals WHERE 
[name] = N'<username>' and [type] IN ('C','E', 'G', 'K', 'S', 'U'))
    CREATE USER [<username>] FOR LOGIN [<loginname>]

Criar função de banco de dados

USE <databasename>
IF NOT EXISTS (SELECT 1 FROM sys.database_principals WHERE 
[name] = N'<rolename>' and Type = 'R')
    CREATE ROLE [<rolename>]

Adicionar usuário à função

USE <databasename>
EXEC sp_addrolemember N'<rolename>', N'<username>'

Conceder direitos ao papel

USE <databasename>
GRANT SELECT ON [<tablename>] TO [<rolename>]
GRANT UPDATE ON [<tablename>] ([<columnname>]) TO [<rolename>]
GRANT EXECUTE ON [<procedurename>] TO [<rolename>]
Henrik Holmgaard Høyer
fonte
-1

Primeiro, você deve verificar a existência do login usando a exibição syslogins:

IF NOT EXISTS 
    (SELECT name  
     FROM master.sys.server_principals
     WHERE name = 'YourLoginName')
BEGIN
    CREATE LOGIN [YourLoginName] WITH PASSWORD = N'password'
END

Então você deve verificar a existência do seu banco de dados:

USE your_dbname

IF NOT EXISTS
    (SELECT name
     FROM sys.database_principals
     WHERE name = 'your_dbname')
BEGIN
    CREATE USER [your_dbname] FOR LOGIN [YourLoginName] 
END
M.Alaghemand
fonte
1
Não sei - dizendo que "você precisa verificar a existência de login usando a exibição syslogins" e publicar um código que não usa essa exibição parece um problema de copiar e colar. Além disso, após a primeira instrução, a linha "Então você precisa verificar a existência do banco de dados", usando o formulário paralelo, parece que você está solicitando a alguém que verifique a existência de um banco de dados, não um usuário no nível do banco de dados. E você precisa especificar que o segundo lote precisa ser executado dentro do banco de dados de destino. No geral, essa é apenas uma explicação muito ruim. E uma vez que você adicionou-lo cinco anos após a maior resposta upvoted disse o mesmo, mas melhor ...
Rindo Vergil