Module Zero安裝


返回《Module Zero學習目錄》



這里需要抱歉的是,這里使用的博客園的Markdown語法,代碼顯示不是很好看,沒有行號,而且外面還有一個雙層框,大家將就着看吧!至於這個雙層框,我也不知道怎么回事,不過博客園官方給的例子是沒雙層框的,如果你知道如何去掉這個框,也麻煩回復一下吧!


使用模板創建(自動方式)##

使用ABP和Module-Zero開始一個新的項目最簡單的方式通過ABP官網的模板頁面創建一個解決方案的模板。看下一篇博客《啟動模板》

手動安裝

如果你之前已經創建了應用,且以后安裝module-zero,那么你可以按下面的步驟來做。

在這篇博客中,我假設你的解決方案有了以下這些項目:

AbpZeroSample.Core
AbpZeroSample.Application
AbpZeroSample.EntityFramework
AbpZeroSample.Web
AbpZeroSample.WebApi

核心(領域)層

將Abp.Zero nuget包安裝到.Core項目中,然后在core module類(本例是AbpZeroSampleCoreModule類)中給AbpZeroCoreModule添加DependsOn特性,如下所示:

[DependsOn(typeof(AbpZeroCoreModule))]  
public class AbpZeroSampleCoreModule : AbpModule  
{  
    public override void Initialize()  
    {  
        IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());  
    }  
}  
    

領域類(實體)

Module-zero提供了抽象類User, Role和Tenant,因此我們應該像下面那樣實現它們:

public class User : AbpUser<Tenant, User>
{

}

public class Role : AbpRole<Tenant, User>
{
    
}

public class Tenant : AbpTenant<Tenant, User>
{

}

你可以在這里添加自定義的屬性。通過這種方式,我們可以根據自己的需求擴展User, Role和Tenant基類。

管理者(領域服務)

因為管理者和存儲基類都是抽象的,所以我們應該實現它們。
讓我們從User存儲和User管理者開始:

public class UserStore : AbpUserStore<Tenant, Role, User>  
{  
    public UserStore(  
        IRepository<User, long> userRepository,  
        IRepository<UserLogin, long> userLoginRepository,  
        IRepository<UserRole, long> userRoleRepository,  
        IRepository<Role> roleRepository,  
        IRepository<UserPermissionSetting, long> userPermissionSettingRepository,  
        IUnitOfWorkManager unitOfWorkManager,  
        ICacheManager cacheManager)    
        : base(  
            userRepository,  
            userLoginRepository,  
            userRoleRepository,  
            roleRepository,  
            userPermissionSettingRepository,  
            unitOfWorkManager,  
            cacheManager)  
    {    
    }      
}    

public class UserManager : AbpUserManager<Tenant, Role, User>  
{  
    public UserManager(  
        UserStore userStore,  
        RoleManager roleManager,  
        IRepository<Tenant> tenantRepository,  
        IMultiTenancyConfig multiTenancyConfig,  
        IPermissionManager permissionManager,  
        IUnitOfWorkManager unitOfWorkManager,  
        ISettingManager settingManager,  
        IUserManagementConfig userManagementConfig,  
        IIocResolver iocResolver,  
        ICacheManager cacheManager  
        )  
        : base(  
        userStore,  
        roleManager,  
        tenantRepository,  
        multiTenancyConfig,  
        permissionManager,  
        unitOfWorkManager,  
        settingManager,  
        userManagementConfig,  
        iocResolver,  
        cacheManager)  
    {  
    }  
}  

不要擔心依賴列表,這可能會在下個版本中改變。如果需要的話,只要排列好構造函數就可以了。這對於RoleStore和RoleManager是相似的。

public class RoleStore : AbpRoleStore<Tenant, Role, User>  
{  
    public RoleStore(  
        IRepository<Role> roleRepository,  
        IRepository<UserRole, long> userRoleRepository,  
        IRepository<RolePermissionSetting, long> rolePermissionSettingRepository,  
        ICacheManager cacheManager)  
        : base(  
            roleRepository,  
            userRoleRepository,  
            rolePermissionSettingRepository,  
            cacheManager)  
    {  
    }  
}  

public class RoleManager : AbpRoleManager<Tenant, Role, User>  
{  
    public RoleManager(  
        RoleStore store,   
        IPermissionManager permissionManager,   
        IRoleManagementConfig roleManagementConfig,   
        ICacheManager cacheManager)  
        : base(  
        store,   
        permissionManager,   
        roleManagementConfig,   
        cacheManager)  
    {  
    }  
}  

這里是租戶管理者(tenant manager),沒有租戶存儲類。

public class TenantManager : AbpTenantManager<Tenant, Role, User>  
{  
    public TenantManager(EditionManager editionManager) :   
        base(editionManager)  
    {  
    }  
}  
 

最后是特征值存儲和版本管理者。


public class FeatureValueStore : AbpFeatureValueStore<Tenant, Role, User>  
{  
    public FeatureValueStore(TenantManager tenantManager)  
        : base(tenantManager)  
    {  
    }  
}  

public class EditionManager : AbpEditionManager  
{  
}  

權限管理者

為了使授權系統生效,我們應該實現權限管理者:

public class PermissionChecker : PermissionChecker<Tenant, Role, User>  
{  
    public PermissionChecker(UserManager userManager)  
        : base(userManager)  
    {  
  
    }  
}  

基礎設施層

EntityFramework

如果你選擇了EntityFramework,那么我們應該給它配置module-zero。將Abp.Zero.EntityFramework nuget包安裝到.EntityFramework項目中,然后在module文件(本例中是AbpZeroSampleDataModule)中,將AbpEntityFrameworkModule依賴改為AbpZeroEntityFrameworkModule,如下所示:

[DependsOn(typeof(AbpZeroEntityFrameworkModule), typeof(AbpZeroSampleCoreModule))]  
public class AbpZeroSampleDataModule : AbpModule  
{  
    //...  
}  

DbContext

在DbContext類中,將基類從AbpDbContext改為AbpZeroDbContext,如下所示:

public class AbpZeroSampleDbContext : AbpZeroDbContext<Tenant, Role, User>  
{  
    //...  
}  

這樣,來自module-zero的實體基類就加到了你的數據庫上下文中。

數據庫遷移(Database Migration)

因為我們的數據庫上下文已經改變了,所以,現在我們應該創建數據庫遷移。打開包管理器控制台,然后輸入以下命令:
Add-Migration "AbpZero_Installed"
當然,你可以選擇一個不同的遷移名字。在包管理器控制台管理器中不要忘了選擇默認的項目為.EntityFramework項目。執行完此命令后,項目中會生成一個新的遷移文件。檢查一下,如果需要的話,你可以做出修改。然后輸入下面的命令來更新數據庫模式:
Update-Database
你可以查看EF Code-First文檔,獲取更多信息。

初始化數據(Initial Data)

如果你檢查了你的數據庫,那么你會發現數據表已經創建了,但是表都是空的。你可以通過EF的種子來初始化數據。你可以使用這么一個類作為初始化數據生成器:

public class DefaultTenantRoleAndUserBuilder   
{  
    private readonly AbpZeroSampleDbContext _context;  

    public DefaultTenantRoleAndUserBuilder(AbpZeroSampleDbContext context)
    {
        _context = context;
    }

    public void Build()
    {
        CreateUserAndRoles();
    }

    private void CreateUserAndRoles()
    {
        //Admin role for tenancy owner

        var adminRoleForTenancyOwner = _context.Roles.FirstOrDefault(r => r.TenantId == null && r.Name == "Admin");
        if (adminRoleForTenancyOwner == null)
        {
            adminRoleForTenancyOwner = _context.Roles.Add(new Role {Name = "Admin", DisplayName = "Admin"});
            _context.SaveChanges();
        }

        //Admin user for tenancy owner

        var adminUserForTenancyOwner = _context.Users.FirstOrDefault(u => u.TenantId == null && u.UserName == "admin");
        if (adminUserForTenancyOwner == null)
        {
            adminUserForTenancyOwner = _context.Users.Add(
                new User
                {
                    TenantId = null,
                    UserName = "admin",
                    Name = "System",
                    Surname = "Administrator",
                    EmailAddress = "admin@aspnetboilerplate.com",
                    IsEmailConfirmed = true,
                    Password = "AM4OLBpptxBYmM79lGOX9egzZk3vIQU3d/gFCJzaBjAPXzYIK3tQ2N7X4fcrHtElTw==" //123qwe
                });

            _context.SaveChanges();

            _context.UserRoles.Add(new UserRole(adminUserForTenancyOwner.Id, adminRoleForTenancyOwner.Id));

            _context.SaveChanges();
        }

        //Default tenant

        var defaultTenant = _context.Tenants.FirstOrDefault(t => t.TenancyName == "Default");
        if (defaultTenant == null)
        {
            defaultTenant = _context.Tenants.Add(new Tenant {TenancyName = "Default", Name = "Default"});
            _context.SaveChanges();
        }

        //Admin role for 'Default' tenant

        var adminRoleForDefaultTenant = _context.Roles.FirstOrDefault(r => r.TenantId == defaultTenant.Id && r.Name == "Admin");
        if (adminRoleForDefaultTenant == null)
        {
            adminRoleForDefaultTenant = _context.Roles.Add(new Role { TenantId = defaultTenant.Id, Name = "Admin", DisplayName = "Admin" });
            _context.SaveChanges();
        }

        //Admin for 'Default' tenant

        var adminUserForDefaultTenant = _context.Users.FirstOrDefault(u => u.TenantId == defaultTenant.Id && u.UserName == "admin");
        if (adminUserForDefaultTenant == null)
        {
            adminUserForDefaultTenant = _context.Users.Add(
                new User
                {
                    TenantId = defaultTenant.Id,
                    UserName = "admin",
                    Name = "System",
                    Surname = "Administrator",
                    EmailAddress = "admin@aspnetboilerplate.com",
                    IsEmailConfirmed = true,
                    Password = "AM4OLBpptxBYmM79lGOX9egzZk3vIQU3d/gFCJzaBjAPXzYIK3tQ2N7X4fcrHtElTw==" //123qwe
                });
            _context.SaveChanges();

            _context.UserRoles.Add(new UserRole(adminUserForDefaultTenant.Id, adminRoleForDefaultTenant.Id));
            _context.SaveChanges();
        }
    }
}

這個類會創建默認的租戶,角色和用戶。我們可以在EF的Configuration類中將種子數據初始化到數據庫:

internal sealed class Configuration : DbMigrationsConfiguration<AbpZeroSample.EntityFramework.AbpZeroSampleDbContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = false;
        ContextKey = "AbpZeroSample";
    }

    protected override void Seed(AbpZeroSample.EntityFramework.AbpZeroSampleDbContext context)
    {
        context.DisableAllFilters();
        new DefaultTenantRoleAndUserBuilder(context).Build();
    }
}

這里,我們禁用了數據過濾器(為的是我們可以自由地操作數據庫)並使用了初始化數據生成器類。

展示層

Nuget包

將下面的nuget包添加到.Web項目中:

  • Abp.Zero.EntityFramework(這個也會添加Abp.Zero和所有依賴)
  • Microsoft.AspNet.Identity.Owin
  • Microsoft.Owin.Host.SystemWeb

Owin Startup類

添加一個Owin Startup類如下:

using AbpZeroSample.Web;
using Microsoft.AspNet.Identity;
using Microsoft.Owin;
using Microsoft.Owin.Security.Cookies;
using Owin;

[assembly: OwinStartup(typeof(Startup))]

namespace AbpZeroSample.Web
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            // Enable the application to use a cookie to store information for the signed in user
            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                LoginPath = new PathString("/Account/Login")
            });

            // Use a cookie to temporarily store information about a user logging in with a third party login provider
            app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
        }
    }
}

Account Controller

我們可以創建一個用於登錄/注銷的控制器,如下:

public class AccountController : AbpZeroSampleControllerBase
{
    private readonly UserManager _userManager;

    private IAuthenticationManager AuthenticationManager
    {
        get
        {
            return HttpContext.GetOwinContext().Authentication;
        }
    }

    public AccountController(UserManager userManager)
    {
        _userManager = userManager;
    }

    public ActionResult Login(string returnUrl = "")
    {
        if (string.IsNullOrWhiteSpace(returnUrl))
        {
            returnUrl = Request.ApplicationPath;
        }

        ViewBag.ReturnUrl = returnUrl;

        return View();
    }

    [HttpPost]
    public async Task<JsonResult> Login(LoginViewModel loginModel, string returnUrl = "")
    {
        if (!ModelState.IsValid)
        {
            throw new UserFriendlyException("Your form is invalid!");
        }

        var loginResult = await _userManager.LoginAsync(
            loginModel.UsernameOrEmailAddress,
            loginModel.Password,
            loginModel.TenancyName
            );

        switch (loginResult.Result)
        {
            case AbpLoginResultType.Success:
                break;
            case AbpLoginResultType.InvalidUserNameOrEmailAddress:
            case AbpLoginResultType.InvalidPassword:
                throw new UserFriendlyException("Invalid user name or password!");
            case AbpLoginResultType.InvalidTenancyName:
                throw new UserFriendlyException("No tenant with name: " + loginModel.TenancyName);
            case AbpLoginResultType.TenantIsNotActive:
                throw new UserFriendlyException("Tenant is not active: " + loginModel.TenancyName);
            case AbpLoginResultType.UserIsNotActive:
                throw new UserFriendlyException("User is not active: " + loginModel.UsernameOrEmailAddress);
            case AbpLoginResultType.UserEmailIsNotConfirmed:
                throw new UserFriendlyException("Your email address is not confirmed!");
            default: //Can not fall to default for now. But other result types can be added in the future and we may forget to handle it
                throw new UserFriendlyException("Unknown problem with login: " + loginResult.Result);
        }

        AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
        AuthenticationManager.SignIn(new AuthenticationProperties { IsPersistent = loginModel.RememberMe }, loginResult.Identity);

        if (string.IsNullOrWhiteSpace(returnUrl))
        {
            returnUrl = Request.ApplicationPath;
        }

        return Json(new MvcAjaxResponse { TargetUrl = returnUrl });
    }

    public ActionResult Logout()
    {
        AuthenticationManager.SignOut();
        return RedirectToAction("Login");
    }
}

還有一個簡單的LoginViewModel類:


	public class LoginViewModel
	{

    public string TenancyName { get; set; }			

    [Required]
    public string UsernameOrEmailAddress { get; set; }

    [Required]
    public string Password { get; set; }

    public bool RememberMe { get; set; }
	}

Login視圖

為了可以使用AccountController,我們應該創建一個login頁面。創建一個login表單取決於你。只需要經由具有合適參數的AJAX調用AccountController的Login方法就可以了。

應用安全

現在,我們可以在HomeController上添加一個AbpAuthorize特性就可以確保只有已經驗證的用戶可以進入該頁面:

[AbpMvcAuthorize]
public class HomeController : AbpZeroSampleControllerBase
{
    public ActionResult Index()
    { 
        return View("~/App/Main/views/layout/layout.cshtml"); //Layout of the angular application.
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM