领域驱动设计实战进阶第一波(十):实现经销商登录仓储与逻辑
DDD实战进阶第一波(十):开发一般业务的大健康行业直销系统(实现经销商登录仓储与逻辑)
上一篇文章主要讲了经销商注册的仓储和领域逻辑的实现,我们先把应用服务协调完成经销商注册这部分暂停一下,后面文章统一讲。
这篇文章主要讲讲经销商登录的仓储和相关逻辑的实现。
在现代应用程序前后端分离的实现中,通常不是将用户登录的信息存储在服务器端Session,因为会存在服务器Session无法传递的情况,也存在WebApi调用时
无法通过Authorize Attribute判断用户是否已经登录并获取用户身份信息的问题。所以现代应用程序都是由服务器后端返回Token给客户端,客户端将Token存储在客户端Session中,客户端在请求后端接口时,带上Token,服务器端就能够识别客户端是否经过身份验证,而且可以直接拿到客户端的身份。
要实现经销商的登录,主要由以下几个步骤组成。
1.实现经销商登录时信息查询的仓储。
2.在应用服务中,单独建立一个查询文件夹放置经销商登录的查询逻辑。
3.在登录WebApi中,调用应用服务的查询逻辑并分发Token。
1.实现经销商登录时信息查询的仓储:
publicinterface ILoginRepository
{
Guid UserLogin(stringtel,string password);
}
publicclass LoginEFCoreRepository : ILoginRepository
{
privatereadonly DbContext context;
public LoginEFCoreRepository(DbContext context)
{
this.context = context;
}
publicGuid UserLogin(stringtel,string password)
{
vardealercontext =this.contextas DealerEFCoreContext;
varenpassword = MD5Encrption.GetMd5Str(password);
varlogindealer= dealercontext.Login.Where(p => p.Code == tel && p.Password == enpassword).FirstOrDefault();
if(logindealer !=null)
{
return logindealer.DealerId;
}
return Guid.Empty;
}
}
2.应用服务中调用仓储完成用户登录的查询
publicclass UserLoginQuery:BaseAppSrv
{
privatereadonly IRepository irepository;
privatereadonly ILoginRepository iloginrepository;
public UserLoginQuery(IRepository irepository, ILoginRepository iloginrepository)
{
this.iloginrepository = iloginrepository;
this.irepository = irepository;
}
public Guid Login(UserLoginDTO userlogindto)
{
try {
using (irepository)
{
return iloginrepository.UserLogin(userlogindto.Telphone, userlogindto.Password);
}
}
catch(Exception error)
{
throw error;
}
}
}
3.在登录WebApi中调用应用服务,并分发令牌
[AllowAnonymous]
[HttpPost]
[Route("UserLogin")]
publicResultEntity UserLogin([FromBody] UserLoginDTO userlogindto)
{
varresult =newResultEntity();
varidealercontext = servicelocator.GetService();
varirepository = servicelocator.GetService(newParameterOverrides { {"context", idealercontext } });
variloginrepository = servicelocator.GetService(newParameterOverrides { {"context", idealercontext } });
UserLoginQuery userloginquery =new UserLoginQuery(irepository, iloginrepository);
try {
vardealerid = userloginquery.Login(userlogindto);
if(dealerid != Guid.Empty)
{
vartoken =new JwtTokenBuilder()
.AddSecurityKey(JwtSecurityKey.Create("msshcjsecretmsshcjsecret"))
.AddSubject(userlogindto.Telphone)
.AddIssuer("DDD1ZXSystem")
.AddAudience("DDD1ZXSystem")
.AddClaim("role","NormalUser")
.AddExpiry(600)
.Build();
varuserloginresultdto =new UserLoginResultDTO();
userloginresultdto.Tel = userlogindto.Telphone;
userloginresultdto.DealerId = dealerid;
userloginresultdto.Token = token.Value;
result.IsSuccess =true;
result.Data = userloginresultdto;
result.Msg ="登录成功!";
}
else {
result.ErrorCode =300;
result.Msg ="登录失败!";
}
}
catch (Exception error)
{
result.ErrorCode =200;
result.Msg = error.Message;
}
return result;
}
这里的UserLoginDTO定义如下:
publicclass UserLoginDTO
{
publicstringTelphone {get;set; }
publicstringPassword {get;set; }
}
这里的UserLoginResultDTO定义如下:
publicclass UserLoginResultDTO
{
publicstringTel {get;set; }
publicGuid DealerId {get;set; }
publicstringToken {get;set; }
}
这里的JwtTokenBuilder定义如下:
publicclass JwtTokenBuilder
{
privateSecurityKey securityKey =null;
privatestringsubject ="";
privatestringissuer ="";
privatestringaudience ="";
privateDictionary claims =newDictionary();
privateintexpiryInMinutes =5;
public JwtTokenBuilder AddSecurityKey(SecurityKey securityKey)
{
this.securityKey = securityKey;
returnthis;
}
publicJwtTokenBuilder AddSubject(string subject)
{
this.subject = subject;
returnthis;
}
publicJwtTokenBuilder AddIssuer(string issuer)
{
this.issuer = issuer;
returnthis;
}
publicJwtTokenBuilder AddAudience(string audience)
{
this.audience = audience;
returnthis;
}
publicJwtTokenBuilder AddClaim(stringtype,string value)
{
this.claims.Add(type, value);
returnthis;
}
publicJwtTokenBuilder AddExpiry(int expiryInMinutes)
{
this.expiryInMinutes = expiryInMinutes;
returnthis;
}
public JwtToken Build()
{
varclaims =newList {
newClaim(JwtRegisteredClaimNames.Sub,this.subject),
new Claim(JwtRegisteredClaimNames.Jti,Guid.NewGuid().ToString())
}.Union(this.claims.Select(item =>new Claim(item.Key, item.Value)));
vartoken =newJwtSecurityToken(issuer:this.issuer, audience:this.audience, claims: claims,
expires: DateTime.UtcNow.AddMinutes(this.expiryInMinutes), signingCredentials:
newSigningCredentials(this.securityKey, SecurityAlgorithms.HmacSha256));
returnnew JwtToken(token);
}
}
这里的BearerUserInfo定义如下:
publicclass BearerUserInfo:Controller
{
publicstring GetUserName()
{
varprincipal = HttpContext.Useras ClaimsPrincipal;
if(principal !=null)
{
foreach(varclaimin principal.Claims)
{
if(claim.Subject !=null)
{
varsubjectclaims = claim.Subject.ClaimsasList;
returnsubjectclaims[0].Value;
}
}
}
returnnull;
}
}
这里的JwtSecurityKey定义如下:
publicstaticclass JwtSecurityKey
{
publicstaticSymmetricSecurityKey Create(string secret)
{
returnnew SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));
}
}
这里的JwtToken定义如下:
publicclass JwtToken
{
private JwtSecurityToken token;
public JwtToken(JwtSecurityToken token)
{
this.token = token;
}
publicDateTime ValidTo => token.ValidTo;
publicstringValue =>newJwtSecurityTokenHandler().WriteToken(this.token);
}
以上采用了.net core中关于OWIN的使用,具体不清楚的属性和方法,可以参考OWIN中.net core的实现标准,这里就不累述了,具体可以参考微信公众号中的视频讲解。
QQ讨论群:309287205
DDD实战进阶视频请关注微信公众号: