领域驱动设计DDD实战进阶第一波(十):开发一般业务的大健康行业直销系统(实现经销商登录仓储与逻辑)

312 阅读3分钟

上一篇文章主要讲了经销商注册的仓储和领域逻辑的实现,我们先把应用服务协调完成经销商注册这部分暂停一下,后面文章统一讲。

这篇文章主要讲讲经销商登录的仓储和相关逻辑的实现。

在现代应用程序前后端分离的实现中,通常不是将用户登录的信息存储在服务器端Session,因为会存在服务器Session无法传递的情况,也存在WebApi调用时 无法通过Authorize Attribute判断用户是否已经登录并获取用户身份信息的问题。所以现代应用程序都是由服务器后端返回Token给客户端,客户端将Token存储在客户端 Session中,客户端在请求后端接口时,带上Token,服务器端就能够识别客户端是否经过身份验证,而且可以直接拿到客户端的身份。

要实现经销商的登录,主要由以下几个步骤组成。

1.实现经销商登录时信息查询的仓储。

2.在应用服务中,单独建立一个查询文件夹放置经销商登录的查询逻辑。

3.在登录WebApi中,调用应用服务的查询逻辑并分发Token。

1.实现经销商登录时信息查询的仓储:

public interface ILoginRepository
{
        Guid UserLogin(string tel, string password);
}

public class LoginEFCoreRepository : ILoginRepository
{
    private readonly DbContext context;
    public LoginEFCoreRepository(DbContext context)
    {
        this.context = context;
    }
    public Guid UserLogin(string tel, string password)
    {
        var dealercontext = this.context as DealerEFCoreContext;
        var enpassword = MD5Encrption.GetMd5Str(password);
        var logindealer=
            dealercontext.Login.Where(p => p.Code == tel && p.Password == enpassword).FirstOrDefault();
        if (logindealer != null)
        {
            return logindealer.DealerId;
        }
        return Guid.Empty;
    }

      }

2.应用服务中调用仓储完成用户登录的查询

public class UserLoginQuery:BaseAppSrv
{
    private readonly IRepository irepository;
    private readonly 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")]
    public ResultEntity<UserLoginResultDTO> UserLogin([FromBody] UserLoginDTO userlogindto)
    {
        var result = new ResultEntity<UserLoginResultDTO>();
        var idealercontext = servicelocator.GetService<IDealerContext>();
        var irepository =
            servicelocator.GetService<IRepository>(new ParameterOverrides { { "context", idealercontext } });
        var iloginrepository = servicelocator.GetService<ILoginRepository>(new ParameterOverrides { { "context", idealercontext } });
        UserLoginQuery userloginquery = new UserLoginQuery(irepository, iloginrepository);
        try
        {
            var dealerid = userloginquery.Login(userlogindto);
            if (dealerid != Guid.Empty)
            {
                var token = new JwtTokenBuilder()
                    .AddSecurityKey(JwtSecurityKey.Create("msshcjsecretmsshcjsecret"))
                    .AddSubject(userlogindto.Telphone)
                    .AddIssuer("DDD1ZXSystem")
                    .AddAudience("DDD1ZXSystem")
                    .AddClaim("role", "NormalUser")                        
                    .AddExpiry(600)
                    .Build();

                var userloginresultdto = 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定义如下:

    public class UserLoginDTO
{
    public string Telphone { get; set; }
    public string Password { get; set; }
}

这里的UserLoginResultDTO定义如下:

 public class UserLoginResultDTO
{
    public string Tel { get; set; }
    public Guid DealerId { get; set; }
    public string Token { get; set; }
}

这里的JwtTokenBuilder定义如下:

public class JwtTokenBuilder
{
    private SecurityKey securityKey = null;
    private string subject = "";
    private string issuer = "";
    private string audience = "";
    private Dictionary<string, string> claims = new Dictionary<string, string>();
    private int expiryInMinutes = 5;

    public JwtTokenBuilder AddSecurityKey(SecurityKey securityKey)
    {
        this.securityKey = securityKey;
        return this;
    }
    public JwtTokenBuilder AddSubject(string subject)
    {
        this.subject = subject;
        return this;
    }
    public JwtTokenBuilder AddIssuer(string issuer)
    {
        this.issuer = issuer;
        return this;
    }
    public JwtTokenBuilder AddAudience(string audience)
    {
        this.audience = audience;
        return this;
    }
    public JwtTokenBuilder AddClaim(string type,string value)
    {
        this.claims.Add(type, value);
        return this;
    }
    public JwtTokenBuilder AddExpiry(int expiryInMinutes)
    {
        this.expiryInMinutes = expiryInMinutes;
        return this;
    }

    public JwtToken Build()
    {
        var claims = new List<Claim>
        {
            new Claim(JwtRegisteredClaimNames.Sub,this.subject),
            new Claim(JwtRegisteredClaimNames.Jti,Guid.NewGuid().ToString())

        }.Union(this.claims.Select(item => new Claim(item.Key, item.Value)));

        var token = new JwtSecurityToken(issuer: this.issuer, audience: this.audience, claims: claims,
            expires: DateTime.UtcNow.AddMinutes(this.expiryInMinutes), signingCredentials:
            new SigningCredentials(this.securityKey, SecurityAlgorithms.HmacSha256));
        return new JwtToken(token);
    }
}

这里的BearerUserInfo定义如下:

public class BearerUserInfo:Controller
{
    public string GetUserName()
    {
        var principal = HttpContext.User as ClaimsPrincipal;
        if (principal != null)
        {
            foreach(var claim in principal.Claims)
            {
                if (claim.Subject != null)
                {
                    var subjectclaims = claim.Subject.Claims as List<Claim>;
                    return subjectclaims[0].Value;
                }
            }
        }
        return null;
    }
}

这里的JwtSecurityKey定义如下:

public static class JwtSecurityKey
{
    public static SymmetricSecurityKey Create(string secret)
    {
        return new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));
    }
}

这里的JwtToken定义如下:

public class JwtToken
{
    private JwtSecurityToken token;
    public JwtToken(JwtSecurityToken token)
    {
        this.token = token;
    }
    public DateTime ValidTo => token.ValidTo;
    public string Value => new JwtSecurityTokenHandler().WriteToken(this.token);
}

以上采用了.net core中关于OWIN的使用,具体不清楚的属性和方法,可以参考OWIN中.net core的实现标准,这里就不累述了,具体可以参考微信公众号中的视频讲解。

DDD实战进阶视频请关注微信公众号:MSSHCJ