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

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

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

在现代应用程序前后端分离的实现中,通常不是将用户登录的信息存储在服务器端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的实现标准,这里就不累述了,具体可以参考微信公众号中的视频讲解。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏JackieZheng

照虎画猫写自己的Spring

从细节跳出来 看了部分Spring的代码,前面用了四篇内容写了一些读书笔记。 回想起来,论复杂度,Spring够喝上好几壶的。他就像一颗枝繁叶茂的大树,远处看...

1866
来自专栏.NET开发那点事

.NET开源高性能Socket通信中间件Helios介绍及演示

  Helios是一套高性能的Socket通信中间件,使用C#编写。Helios的开发受到Netty的启发,使用非阻塞的事件驱动模型架构来实现高并发高吞吐量。H...

832
来自专栏架构师之旅

《Spring敲门砖之基础教程第一季》 第一章(2)解读Spring Framework

系统架构 一个成功的项目离不开一个好的架构,一个好的架构自然需要一位好的设计师, Rod Johnson正是Spring的前生总架构设计师,那...

1736
来自专栏Hongten

Struts2 IncludeModules(包含 <include file="login.xml" />)

xml文件当成struts.xml包含在struts.xml中,比如我们看到的login.xml

441
来自专栏程序员的SOD蜜

“一切都是消息”--MSF(消息服务框架)之【请求-响应】模式(点对点)

在前一篇, “一切都是消息”--MSF(消息服务框架)入门简介, 我们介绍了MSF基于异步通信,支持请求-响应通信模式和发布-订阅通信模式,并且介绍了如何获取M...

3838
来自专栏码农笔录

Android全能开源项目xUtils3开发教程、简单封装

1062
来自专栏一个会写诗的程序员的博客

Spring 5.0.3.RELEASE中的 Kotlin 语言等支持Spring 5.0.3.RELEASE中的 Kotlin 语言支持

https://docs.spring.io/spring/docs/current/spring-framework-reference/languages....

1193
来自专栏晓晨的专栏

.NET Core 开源工具 IPTools - 快速查询 IP 地理位置、经纬度信息

快速查询IP信息,支持国内和国外IP信息查询,支持查询经纬度,地理位置最高支持到城市。

912
来自专栏青玉伏案

类比Spring框架来实现OC中的依赖注入

如果你之前使用过JavaEE开发中的Spring框架的话,那么你一定对依赖注入并不陌生。依赖注入(DI: Dependency Injection)是控制反转(...

2009
来自专栏NetCore

[原创]Fluent NHibernate之旅二--Entity Mapping

接着上一篇,今天我们说说ORM中的Mapping。如果你要体验NHibernate的强大,首先你就要学会配置,包括SessionFactory和Mapping的...

1999

扫码关注云+社区