[C# 서버] Account Server

이정석·2023년 9월 20일
0

CSharpServer

목록 보기
13/13

Account Server

로그인 처리를 위한 Account Server는 하나의 웹서버로 만들 수 있다. C#에서 웹서버를 만들기 위해서 ASP.NET Core를 사용할 수 있는데 사용자 계정에 대한 DB모델을 정의하고 일종의 RESTful API를 구축해 로그인 기능을 구현할 수 있다.

1. ASP.NET Core

'ASP.NET Core'는 마이크로소프트에서 제공하는 프레임워크로 이를 이용해 웹 어플리케이션이나 API를 만들 수 있다.

Visual Studio를 사용한다면, Visual Studio에는 ASP.NET Core에서 제공하는 여러가지 웹 어플리케이션 템플릿이 있다. 웹앱, 웹 API, MVC모델구조 등 여러가지를 지원한다.

2. Main

    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);

            // Add services to the container.
            // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
            builder.Services.AddEndpointsApiExplorer();
            builder.Services.AddSwaggerGen();

            var app = builder.Build();

            // Configure the HTTP request pipeline.
            if (app.Environment.IsDevelopment())
            {
                app.UseSwagger();
                app.UseSwaggerUI();
            }

            app.UseHttpsRedirection();

            app.UseAuthorization();


            app.MapControllers();

            app.Run();
        }
    }

처음 생성되는 Main함수는 크게 두 부분으로 나눌 수 있다.

  1. 어플리케이션의 기능을 설정하는 builder
  2. 실제 서비스 단계(인증, 라우팅)을 설정하는 app

builder는 서비스외의 실행환경이나 구성, 로깅, 호스트 설정같은 어플리케이션의 다양한 부분을 설정하는 객체로 사용자가 정의한 Controller에 대한 규칙도 정의할 수 있다.

app은 HTTP 요청 파이프라인을 구성하는데 사용되는 객체로 미들웨어나 라우팅등 사용자 요청이 어디로 연결되는지에 대한 환경을 설정할 수 있다.


DB

[C# 서버] DB - EFC, CRUD에서 Entity를 정의하는 법과 DbContext에 대한 내용을 간략하게 얘기했었는데 Account Server에서 사용할 Account 테이블은 아래와 같이 정의할 수 있다.

    [Table("Account")]
    public class AccountDb
    {
        public int AccountDbId { get; set; }
        public string AccountName { get; set; }
        public string Password { get; set; }
    }

1. Packet

public class CreateAccountPacketReq
{
    public string AccountName { get; set; }
    public string Password { get; set; }
}

public class CreateAccountPacketRes
{
    public bool CreateOk { get; set; }
}

public class LoginAccountPacketReq
{
    public string AccountName { get; set; }
    public string Password { get; set; }
}

public class ServerInfo
{
    public string Name { get; set; }
    public string Ip { get; set; }
    public int CrowdedLevel { get; set; }
}

public class LoginAccountPacketRes
{
    public bool LoginOk { get; set; }
    public List<ServerInfo> ServerList { get; set; } = new List<ServerInfo>();
}

웹서버는 실시간 상호작용이 주 기능이 아니지만 게임서버처럼 클라이언트-서버가 주고 받을 패킷에 대한 정의가 필요하다. 로그인, 회원가입의 요청-응답에 대한 패킷정의는 위와 같이 할 수 있다.

서버는 클라이언트가 보낸 요청을 해석, 처리해야하기 때문에 요청패킷의 구조와 데이터에 대해서 알고 있어야하고 반대로 클라이언트 역시 서버가 전달한 응답을 해석, 처리하기 위해 응답패킷의 구조와 데이터에 대해서 알고 있어야 한다.

2. Controller

    [Route("api/[controller]")]
    [ApiController]
    public class AccountController : ControllerBase
    {
        AppDbContext _context;

        public AccountController(AppDbContext context)
        {
            _context = context;
        }

        [HttpPost]
        [Route("create")]
        public CreateAccountPacketRes CreateAccount([FromBody] CreateAccountPacketReq req)
        {
            CreateAccountPacketRes res = new CreateAccountPacketRes();

            AccountDb account = _context.Accounts
                .AsNoTracking()
                .Where(a => a.AccountName == req.AccountName)
                .FirstOrDefault();

            if(account == null)
            {
                _context.Accounts.Add(new AccountDb()
                {
                    AccountName = req.AccountName,
                    Password = req.Password
                });

                bool success = _context.SaveChangesEx();
                res.CreateOk = success;
            }
            else
            {
                res.CreateOk = false;
            }

            return res;
        }

        [HttpPost]
        [Route("login")]
        public LoginAccountPacketRes LoginAccount([FromBody] LoginAccountPacketReq req)
        {
            LoginAccountPacketRes res = new LoginAccountPacketRes();

            AccountDb account = _context.Accounts
                .AsNoTracking()
                .Where(a=>a.AccountName == req.AccountName && a.Password==req.Password)
                .FirstOrDefault();

            if (account == null)
            {
                res.LoginOk = false;
            }
            else
            {
                res.LoginOk = true;

                res.ServerList = new List<ServerInfo>()
                {
                    new ServerInfo() { Name = "아메리카노", Ip = "127.0.0.1", CrowdedLevel = 0},
                    new ServerInfo() { Name = "민트초코라떼", Ip = "127.0.0.1", CrowdedLevel = 3}
                };
            }

            return res;
        }
    }

ASP.NET Core의 Controller 폴더에 Controller를 생성하면 ControllerBase를 상속받는 사용자 정의 Controller를 구현할 수 있다.

  1. 'api/Account'에 대한 컨트롤러임을 나타낸다.
    [Route("api/[controller]")]
    [ApiController]
    public class AccountController : ControllerBase
  1. AccountController 클래스는 AccountController의 Account Table에 접근하기 위해 AppDbContext를 가지고 있다.
    AppDbContext _context;

    public AccountController(AppDbContext context)
    {
        _context = context;
    }
  1. 회원가입을 처리하기 위한 함수로 함수위에 'POST'를 사용할 것과 'create'라우팅 즉, api/Account/create의 POST요청에 대한 컨트롤러를 담당하는 함수이다.
    [HttpPost]
    [Route("create")]
    public CreateAccountPacketRes CreateAccount([FromBody] CreateAccountPacketReq req)

매개변수의 [FromBody]는 패킷 Body에 있는 값을 파싱할 것을 의미한다. 입력값과 반환값을 보면 요청패킷(~Req)를 받고 반환값은 응답패킷(~Res)인 것을 알아두자.

  1. 로그인을 처리하기 위한 함수로 함수위에 'POST'를 사용할 것과 'login'라우팅(api/Account/create)요청에 대한 컨트롤러를 담당하는 함수이다.
    [HttpPost]
    [Route("login")]
    public LoginAccountPacketRes LoginAccount([FromBody] LoginAccountPacketReq req)

회원가입과 마찬가지로 입력값, 반환값의 패킷차이를 알아두자. 함수에서 DB에 접근하는 코드는 아래와 같다.

  • AsNoTracking: 읽기만 한다는 것을 명시해 값을 가져오는 속도를 조금 높일 수 있다.
  • Where: SQL문의 WHERE절로 조건식을 만족하는 값을 가져올것을 의미한다.
  • FirstOrDefault: 검색된 값의 첫번째 값을 가져온다. 값이 없다면 Null을 반환한다.
    AccountDb account = _context.Accounts
        .AsNoTracking()
        .Where(a=>a.AccountName == req.AccountName && a.Password==req.Password)
        .FirstOrDefault();

Account Server의 설정을 위해 메인함수에 다음과 같은 builder 설정을 해준다. Json 파싱과정의 Policy를 초기화 시키고 DBMS의 연결정보는 Configuration의 내용을 참고하라는 설정이다.

    builder.Services.AddControllers().AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.PropertyNamingPolicy = null;
        options.JsonSerializerOptions.DictionaryKeyPolicy = null;
    });

    builder.Services.AddDbContext<AppDbContext>(options =>
    {
        options.UseSqlServer(builder.Configuration["ConnectionStrings:DefaultConnection"]);
    });
profile
게임 개발자가 되고 싶은 한 소?년

0개의 댓글