Sql-Server
授予對帳戶的 dbmail 訪問權限
我們有一個帶有許多(不斷增加的)數據庫的伺服器,每個“數據庫”都需要能夠使用 dbmail。每個(數據庫的)郵件帳戶都是不同的,並通過自定義 ui 進行配置。我們創建了一個儲存過程,可以多次執行它來添加必要的 msdb.dbo.sysmail_profile 和 msdb.dbo.sysmail_account。其中的內容來自:在 SQL Server 2008 中使用數據庫郵件
CREATE PROC ai_SetupSMTPEmailProfileAndAccounts AS --adds profile if not exists or gets profile id --adds account if not exists or gets account id --adds account to profile if not exists --makes account profile public for use --http://www.idevelopment.info/data/SQLServer/DBA_tips/Database_Administration/DBA_20.shtml DECLARE @DatabaseName VARCHAR(256) DECLARE @EmailAccountDescription VARCHAR(256) DECLARE @SMTPServerName VARCHAR(256) DECLARE @SMTPPort INT DECLARE @SMTPAccountName VARCHAR(256) DECLARE @SMTPPassword VARCHAR(256) DECLARE @SMTPFromAddress VARCHAR(256) DECLARE @SSL INT = 0 DECLARE @DefaultCredentials INT = 0 DECLARE @AccountNr INT = 0 DECLARE @ProfileNr INT = 0 SET @DatabaseName = DB_NAME() SET @EmailAccountDescription = @DatabaseName + ' email sending account' IF (@DatabaseName = 'master') OR (@DatabaseName = 'msdb') OR (@DatabaseName = 'model') OR (@DatabaseName = 'tempdb') BEGIN PRINT 'Do not run on ' + @DatabaseName RETURN END ELSE BEGIN IF NOT EXISTS( SELECT * FROM msdb.dbo.sysmail_profile WHERE name = @DatabaseName) BEGIN PRINT 'profile not exists' EXECUTE msdb.dbo.sysmail_add_profile_sp @profile_name = @DatabaseName , @description = 'auto db specific smtp profile' , @profile_id = @ProfileNr OUTPUT --yup sql has the output prameters the wrong way around END ELSE BEGIN PRINT 'profile exists' SET @ProfileNr = (SELECT TOP 1 profile_id FROM msdb.dbo.sysmail_profile WHERE name = @DatabaseName) END IF NOT EXISTS( SELECT * FROM msdb.dbo.sysmail_account WHERE name = @DatabaseName) BEGIN PRINT 'account not exists' SELECT TOP 1 @SMTPServerName = CASE WHEN COALESCE(WebAppSmtpServer, '') <> '' THEN WebAppSmtpServer COLLATE SQL_Latin1_General_CP1_CI_AS ELSE COALESCE(DbMSmtpServer, '') COLLATE SQL_Latin1_General_CP1_CI_AS END , @SMTPPort = CASE WHEN COALESCE(WebAppSMTPPort, 587) <> 587 THEN WebAppSMTPPort ELSE COALESCE(DbMSMTPPort, 587) END , @SMTPAccountName = CASE WHEN COALESCE(WebAppSMTPUser, '') <> '' THEN WebAppSMTPUser COLLATE SQL_Latin1_General_CP1_CI_AS ELSE COALESCE(DbMSMTPUser, '') COLLATE SQL_Latin1_General_CP1_CI_AS END , @SMTPPassword = CASE WHEN COALESCE(WebAppSMTPPwd, '') <> '' THEN WebAppSMTPPwd COLLATE SQL_Latin1_General_CP1_CI_AS ELSE COALESCE(DbMSMTPPwd, '') COLLATE SQL_Latin1_General_CP1_CI_AS END , @SMTPFromAddress = CASE WHEN COALESCE(WebAppSMTPFrom, '') <> '' THEN WebAppSMTPFrom COLLATE SQL_Latin1_General_CP1_CI_AS ELSE COALESCE(DbMSMTPFrom, '') COLLATE SQL_Latin1_General_CP1_CI_AS END , @SSL = CASE WHEN COALESCE(WebAppSMTPSSL, 0) >= 2 THEN --sql and sql external 1 WHEN COALESCE(DbMSMTPSSL, 0) >= 2 THEN --sql and sql external 1 ELSE 0 END , @DefaultCredentials = CASE WHEN COALESCE(WebAppSMTPSSL, 0) = 3 THEN --sql and sql external 1 ELSE 0 END FROM Rules2 ORDER BY RulesKey2 PRINT 'rules 2 setting checked' EXECUTE msdb.dbo.sysmail_add_account_sp @email_address = @SMTPFromAddress , @account_name = @DatabaseName , @display_name = @DatabaseName , @replyto_address = @SMTPFromAddress , @description = @EmailAccountDescription , @mailserver_name = @SMTPServerName --[ , [ @mailserver_type = ] 'server_type' ] 'optional only SMTP supported' , @port = @SMTPPort , @username = @SMTPAccountName , @password = @SMTPPassword , @use_default_credentials = 0 -- we will always have nor domain credientials @DefaultCredentials --use account name and password --not databse credentials , @enable_ssl = @SSL -- bit 1 for use ssl , @account_id = @AccountNr OUTPUT PRINT '@SMTPFromAddress:' + ISNULL(@SMTPFromAddress, ' NULL') PRINT '@DatabaseName:' + ISNULL(@DatabaseName, ' NULL') PRINT '@EmailAccountDescription:' + ISNULL(@EmailAccountDescription, ' NULL') PRINT '@SMTPServerName:' + ISNULL(@SMTPServerName, ' NULL') PRINT '@SMTPPort:' + CAST(ISNULL(@SMTPPort, 0) AS VARCHAR(15)) PRINT '@SMTPAccountName:' + ISNULL(@SMTPAccountName, ' NULL') PRINT '@SMTPPassword:' + ISNULL(@SMTPPassword, ' NULL') PRINT '@DefaultCredentials:' + CAST(ISNULL(@DefaultCredentials, 0) AS VARCHAR(15)) PRINT '@SSL:' + CAST(ISNULL(@SSL, 0) AS VARCHAR(15)) PRINT 'tried to add account' END ELSE BEGIN PRINT 'account exists' SET @AccountNr = ( SELECT TOP 1 account_id FROM msdb.dbo.sysmail_account WHERE name = @DatabaseName ORDER BY account_id ) SELECT TOP 1 @SMTPServerName = CASE WHEN COALESCE(WebAppSmtpServer, '') <> '' THEN WebAppSmtpServer COLLATE SQL_Latin1_General_CP1_CI_AS ELSE COALESCE(DbMSmtpServer, '') COLLATE SQL_Latin1_General_CP1_CI_AS END , @SMTPPort = CASE WHEN COALESCE(WebAppSMTPPort, 587) <> 587 THEN WebAppSMTPPort ELSE COALESCE(DbMSMTPPort, 587) END , @SMTPAccountName = CASE WHEN COALESCE(WebAppSMTPUser, '') <> '' THEN WebAppSMTPUser COLLATE SQL_Latin1_General_CP1_CI_AS ELSE COALESCE(DbMSMTPUser, '') COLLATE SQL_Latin1_General_CP1_CI_AS END , @SMTPPassword = CASE WHEN COALESCE(WebAppSMTPPwd, '') <> '' THEN WebAppSMTPPwd COLLATE SQL_Latin1_General_CP1_CI_AS ELSE COALESCE(DbMSMTPPwd, '') COLLATE SQL_Latin1_General_CP1_CI_AS END , @SMTPFromAddress = CASE WHEN COALESCE(WebAppSMTPFrom, '') <> '' THEN WebAppSMTPFrom COLLATE SQL_Latin1_General_CP1_CI_AS ELSE COALESCE(DbMSMTPFrom, '') COLLATE SQL_Latin1_General_CP1_CI_AS END , @SSL = CASE WHEN COALESCE(WebAppSMTPSSL, 0) >= 2 THEN --sql and sql external 1 WHEN COALESCE(DbMSMTPSSL, 0) >= 2 THEN --sql and sql external 1 ELSE 0 END , @DefaultCredentials = CASE WHEN COALESCE(WebAppSMTPSSL, 0) = 3 THEN --sql and sql external 1 ELSE 0 END FROM Rules2 ORDER BY RulesKey2 EXECUTE msdb.dbo.sysmail_update_account_sp @account_id = @AccountNr , @email_address = @SMTPFromAddress , @account_name = @DatabaseName , @display_name = @DatabaseName , @replyto_address = @SMTPFromAddress , @description = @EmailAccountDescription , @mailserver_name = @SMTPServerName --[ , [ @mailserver_type = ] 'server_type' ] 'optional only SMTP supported' , @port = @SMTPPort , @username = @SMTPAccountName , @password = @SMTPPassword , @use_default_credentials = 0 -- we will always have nor domain credientials @DefaultCredentials --use account name and password --not databse credentials , @enable_ssl = @SSL -- bit 1 for use ssl END PRINT CAST(@ProfileNr AS VARCHAR(15)) + ' @ProfileNr' PRINT CAST(@AccountNr AS VARCHAR(15)) + ' @AccountNr' -- the following are necessary !!! IF NOT EXISTS(SELECT * FROM msdb.dbo.sysmail_profileaccount WHERE profile_id = @ProfileNr AND account_id = @AccountNr) BEGIN -- Add the account to the profile EXECUTE msdb.dbo.sysmail_add_profileaccount_sp @profile_name = @DatabaseName, @account_name = @DatabaseName, @sequence_number = 1 ; END IF NOT EXISTS(SELECT * FROM msdb.dbo.sysmail_principalprofile WHERE profile_id = @ProfileNr) BEGIN -- Grant access to the profile to all users in the msdb database EXECUTE msdb.dbo.sysmail_add_principalprofile_sp @profile_name = @DatabaseName, @principal_name = 'public', @is_default = 1 ; END --SELECT name, [Description], profile_id, 0 account_id, 'profile' TableName FROM msdb.dbo.sysmail_profile --UNION --SELECT name, [Description], 0 profile_id, account_id, 'email account' TableName FROM msdb.dbo.sysmail_account END --cycle db mail mail status EXEC Master.dbo.sp_configure 'Database Mail XPs', 0 RECONFIGURE EXEC Master.dbo.sp_configure 'Database Mail XPs', 1 RECONFIGURE RETURN
所以我們只執行 proc,然後從每個數據庫中查找實際的帳戶設置。問題是我們缺少一些權限,需要編寫腳本。理想情況下,這應該構成我們上面儲存過程的一部分(文章中的程式碼)
USE [master] Go -- Create a login account to use Windows Authentication CREATE LOGIN [IDEVELOPMENT\AppUser] FROM WINDOWS WITH DEFAULT_DATABASE = [AppDB]; Go -- -- Create a user in the [msdb] database USE [msdb] Go CREATE USER [AppUser] FOR LOGIN [IDEVELOPMENT\AppUser]; Go GRANT CONNECT TO [AppUser]; Go -- USE [msdb] Go -- Add user to the Database Mail role EXEC sp_addrolemember @rolename = 'DatabaseMailUserRole' , @membername = 'AppUser'; Go -- Grants permission for a database user or role -- to use a private Database Mail profile EXEC msdb.dbo.sysmail_add_principalprofile_sp @profile_name = 'iDevelopment.info Profile' , @principal_name = 'AppUser' , @is_default = 1; Go
在這一點上,我已經達到了我對 SQL 腳本工作的知識的極限。那麼有人可以建議一種方法來避免在 procs 中不允許的“使用”嗎?
動態字元串執行將允許您在 proc 中執行 USE dbname。請注意,如果您在這些語句之後在目前數據庫中執行語句,則必須切換回它。
DECLARE @sql varchar(max) SET @sql = ' USE [master] -- Create a login account to use Windows Authentication CREATE LOGIN [IDEVELOPMENT\AppUser] FROM WINDOWS WITH DEFAULT_DATABASE = [AppDB]; ' -- -- Create a user in the [msdb] database EXEC(@sql) SET @sql = ' USE [msdb] CREATE USER [AppUser] FOR LOGIN [IDEVELOPMENT\AppUser]; GRANT CONNECT TO [AppUser]; -- Add user to the Database Mail role EXEC sp_addrolemember @rolename = ''DatabaseMailUserRole'' , @membername = ''AppUser''; -- Grants permission for a database user or role -- to use a private Database Mail profile EXEC msdb.dbo.sysmail_add_principalprofile_sp @profile_name = ''iDevelopment.info Profile'' , @principal_name = ''AppUser'' , @is_default = 1; Go ' EXEC (@sql)