1
0
mirror of https://github.com/rudollee/LearningMVC.git synced 2025-06-06 15:36:11 +00:00

Ch. 12 SportsStore Security and Finish

This commit is contained in:
wook 2017-04-10 01:47:50 +09:00
parent 7841e9077e
commit 933829c866
14 changed files with 215 additions and 14 deletions

View File

@ -31,6 +31,8 @@ namespace SportsStore.Domain.Concrete
dbEntry.Description = product.Description;
dbEntry.Price = product.Price;
dbEntry.Category = product.Category;
dbEntry.ImageData = product.ImageData;
dbEntry.ImageMimeType = product.ImageMimeType;
}
}

View File

@ -25,5 +25,8 @@ namespace SportsStore.Domain.Entities
[Required(ErrorMessage = "Please specify a category")]
public string Category { get; set; }
public byte[] ImageData { get; set; }
public string ImageMimeType { get; set; }
}
}

View File

@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using SportsStore.WebUI.Infrastructure.Abstract;
using SportsStore.WebUI.Models;
namespace SportsStore.WebUI.Controllers
{
public class AccountController : Controller
{
IAuthProvider authProvider;
public AccountController(IAuthProvider auth)
{
authProvider = auth;
}
public ViewResult Login()
{
return View();
}
[HttpPost]
public ActionResult Login(LoginViewModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (authProvider.Authenticate(model.UserName, model.Password))
{
return Redirect(returnUrl ?? Url.Action("Index", "Admin"));
}
else
{
ModelState.AddModelError("", "Incorrect username or password");
return View();
}
}
else
{
return View();
}
}
}
}

View File

@ -8,6 +8,7 @@ using SportsStore.Domain.Entities;
namespace SportsStore.WebUI.Controllers
{
[Authorize]
public class AdminController : Controller
{
private IProductRepository repository;
@ -30,10 +31,16 @@ namespace SportsStore.WebUI.Controllers
}
[HttpPost]
public ActionResult Edit(Product product)
public ActionResult Edit(Product product, HttpPostedFileBase image = null)
{
if (ModelState.IsValid)
{
if (image != null)
{
product.ImageMimeType = image.ContentType;
product.ImageData = new byte[image.ContentLength];
image.InputStream.Read(product.ImageData, 0, image.ContentLength);
}
repository.SaveProduct(product);
TempData["message"] = string.Format("{0} has been saved", product.Name);
return RedirectToAction("Index");

View File

@ -53,5 +53,17 @@ namespace SportsStore.WebUI.Controllers
return View(model);
}
public FileContentResult GetImage(int productId)
{
Product prod = repository.Products.FirstOrDefault(p => p.ProductID == productId);
if (prod != null)
{
return File(prod.ImageData, prod.ImageMimeType);
}
else
{
return null;
}
}
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SportsStore.WebUI.Infrastructure.Abstract;
namespace SportsStore.WebUI.Infrastructure.Abstract
{
public interface IAuthProvider
{
bool Authenticate(string username, string password);
}
}

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using SportsStore.WebUI.Infrastructure.Abstract;
namespace SportsStore.WebUI.Infrastructure.Concrete
{
public class FormsAuthProvider : IAuthProvider
{
public bool Authenticate(string username, string password)
{
bool result = FormsAuthentication.Authenticate(username, password);
if (result)
{
FormsAuthentication.SetAuthCookie(username, false);
}
return result;
}
}
}

View File

@ -9,6 +9,8 @@ using Ninject;
using SportsStore.Domain.Abstract;
using SportsStore.Domain.Concrete;
using SportsStore.Domain.Entities;
using SportsStore.WebUI.Infrastructure.Abstract;
using SportsStore.WebUI.Infrastructure.Concrete;
namespace SportsStore.WebUI.Infrastructure
{
@ -51,7 +53,7 @@ namespace SportsStore.WebUI.Infrastructure
kernel.Bind<IOrderProcessor>().To<EmailOrderProcessor>().WithConstructorArgument("settings", emailSettings);
kernel.Bind<IAuthProvider>().To<FormsAuthProvider>();
}
}
}

View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
namespace SportsStore.WebUI.Models
{
public class LoginViewModel
{
[Required]
public string UserName { get; set; }
[Required]
public string Password { get; set; }
}
}

View File

@ -141,6 +141,7 @@
<ItemGroup>
<Compile Include="App_Start\NinjectWebCommon.cs" />
<Compile Include="App_Start\RouteConfig.cs" />
<Compile Include="Controllers\AccountController.cs" />
<Compile Include="Controllers\AdminController.cs" />
<Compile Include="Controllers\CartController.cs" />
<Compile Include="Controllers\NavController.cs" />
@ -149,9 +150,12 @@
<DependentUpon>Global.asax</DependentUpon>
</Compile>
<Compile Include="HtmlHelpers\PagingHelpers.cs" />
<Compile Include="Infrastructure\Abstract\IAuthProvider.cs" />
<Compile Include="Infrastructure\Binders\CartModelBinder.cs" />
<Compile Include="Infrastructure\Concrete\FormsAuthProvider.cs" />
<Compile Include="Infrastructure\NinjectDependencyResolver.cs" />
<Compile Include="Models\CartIndexViewModel.cs" />
<Compile Include="Models\LoginViewModel.cs" />
<Compile Include="Models\PagingInfo.cs" />
<Compile Include="Models\ProductsListViewModel.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
@ -177,6 +181,7 @@
<Content Include="Views\Shared\_AdminLayout.cshtml" />
<Content Include="Views\Admin\Index.cshtml" />
<Content Include="Views\Admin\Edit.cshtml" />
<Content Include="Views\Account\Login.cshtml" />
<None Include="Web.Debug.config">
<DependentUpon>Web.config</DependentUpon>
</None>

View File

@ -0,0 +1,27 @@
@model SportsStore.WebUI.Models.LoginViewModel
@{
ViewBag.Title = "Admin: Log in";
Layout = "~/Views/Shared/_AdminLayout.cshtml";
}
<div class="panel">
<div class="panel-heading">
<h3>Log in</h3>
</div>
<div class="panel-body">
<p class="lead">Please log in to access the administration area:</p>
@using (Html.BeginForm())
{
@Html.ValidationSummary()
<div class="form-group">
<label>User Name:</label>
@Html.TextBoxFor(m => m.UserName, new { @class = "form-control"})
</div>
<div class="form-group">
<label>Password:</label>
@Html.PasswordFor(m => m.Password, new { @class = "form-control"})
</div>
<input type="submit" value="Log in" class="btn btn-primary" />
}
</div>
</div>

View File

@ -18,28 +18,58 @@
<h3>Edit @Model.Name</h3>
</div>
@using (Html.BeginForm("Edit", "Admin"))
@using (Html.BeginForm("Edit", "Admin", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="panel-body">
@Html.HiddenFor(m => m.ProductID)
@foreach (var property in ViewData.ModelMetadata.Properties)
{
if (property.PropertyName != "ProeuctID")
switch (property.PropertyName)
{
<div class="form-group">
<label>@(property.DisplayName ?? property.PropertyName)</label>
@if (property.PropertyName == "Description")
case "ProductID":
case "ImageData":
case "ImageMimeType":
break;
default:
if (property.PropertyName != "ProeuctID")
{
@Html.TextArea(property.PropertyName, null, new { @class = "form-control", rows = 5 })
<div class="form-group">
<label>@(property.DisplayName ?? property.PropertyName)</label>
@if (property.PropertyName == "Description")
{
@Html.TextArea(property.PropertyName, null, new { @class = "form-control", rows = 5 })
}
else
{
@Html.TextBox(property.PropertyName, null, new { @class = "form-control" })
}
@Html.ValidationMessage(property.PropertyName)
</div>
}
else
{
@Html.TextBox(property.PropertyName, null, new { @class = "form-control" })
}
@Html.ValidationMessage(property.PropertyName)
</div>
break;
}
}
<div class="form-group">
<div style="position:relative;">
<label>Image</label>
<a class="btn" href="javascript:;">
Choose File...
<input type="file" name="Image" size="40"
style="position:absolute; z-index:2; top: 0; left: 0; filter: alpha(opacity=0); opacity: 0; background-color: transparent; color: transparent;"
onchange="$("#upload-file-info").html($(this).val());' />
</a>
<span class="label label-info" id="upload-file-info" />
</div>
@if (Model.ImageData == null)
{
<div class="form-control-static">No Image</div>
}
else
{
<img class="img-thumbnail" width="150" height="150" src="@Url.Action("GetImage", "Product", new { Model.ProductID })" />
}
</div>
</div>
<div class="panel-footer">

View File

@ -1,6 +1,12 @@
@model SportsStore.Domain.Entities.Product
<div class="well">
@if (Model.ImageData != null)
{
<div class="pull-left" style="margin-right: 10px">
<img class="img-thumbnail" width="75" height="75" src="@Url.Action("GetImage", "Product", new { Model.ProductID })" />
</div>
}
<h3>
<strong>@Model.Name</strong>
<span class="pull-right label label-primary">@Model.Price</span>

View File

@ -22,6 +22,13 @@
<compilation debug="true" targetFramework="4.5.2" />
<httpRuntime targetFramework="4.5.2" />
<globalization culture="en-US" uiCulture="en-US" />
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="2880" >
<credentials passwordFormat="Clear">
<user name="admin" password="secret"/>
</credentials>
</forms>
</authentication>
</system.web>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">