· 6 years ago · Nov 05, 2019, 12:52 PM
1// az appsettings.json fajlban hozza kell adni egy titkos kulcsot:
2{
3 "ConnectionStrings": {
4 "RestaurantDbConnection": "..."
5 },
6
7// ez nalam valtozatlan marad, mindegy milyen kulcsot irsz ide
8 "AppSettings": {
9 "SecretKey": "y8xeYDKkn6ZOSo9fI99Hr6H706am0Y"
10 }
11}
12
13
14
15
16
17
18 // hozd letre ezt az osztalyt:
19 public class AppSettings
20 {
21 public string SecretKey { get; set; }
22 }
23
24//Program osztalyom (sztem itt nem nagyon kell valtoztatnod)
25public class Program
26 {
27 public static void Main(string[] args)
28 {
29 BuildWebHost(args).Run();
30 }
31
32 public static IWebHost BuildWebHost(string[] args) =>
33
34 WebHost.CreateDefaultBuilder(args)
35 .UseKestrel()
36 .UseContentRoot(Directory.GetCurrentDirectory())
37 .UseIISIntegration()
38 .UseStartup<Startup>()
39 .Build();
40 }
41
42 // Startup osztalyom:
43 public class Startup
44 {
45 public IConfiguration Configuration { get; }
46
47 public Startup(IConfiguration configuration)
48 {
49 Configuration = configuration;
50 }
51
52 public void ConfigureServices(IServiceCollection services)
53 {
54 #region Fontos dolgok.
55 //A titkos kulcs alapjan hozzaad egy Authentication es egy JwtBearer Service-t a ServiceCollectoin-hoz
56 var appSettingsSection = Configuration.GetSection("AppSettings");
57 services.Configure<AppSettings>(appSettingsSection);
58
59 var appSettings = appSettingsSection.Get<AppSettings>();
60 var key = Encoding.ASCII.GetBytes(appSettings.SecretKey);
61 services.AddAuthentication(x =>
62 {
63 x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
64 x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
65 })
66 .AddJwtBearer(x =>
67 {
68 x.RequireHttpsMetadata = false;
69 x.SaveToken = true;
70 x.TokenValidationParameters = new TokenValidationParameters
71 {
72 ValidateIssuerSigningKey = true,
73 IssuerSigningKey = new SymmetricSecurityKey(key),
74 ValidateIssuer = false,
75 ValidateAudience = false,
76 ClockSkew = TimeSpan.Zero
77 };
78 });
79
80 // fontos fuggosegek:
81 services.AddScoped<ITokenGeneratorService, JwtTokenGeneratorService>();
82 services.AddScoped<IAuthenticationService, AuthenticationService>();
83 #endregion
84
85 // a tobbi nem fontos
86 services.AddScoped<IPermissionValidatorService, PermissionValidatorService>();
87 services.AddTransient(typeof(IObjectMapperService<,>), typeof(ObjectMapperService<,>));
88
89 services.AddEntityFrameworkNpgsql().AddDbContext<RestaurantDbContext>
90 (options => options.UseNpgsql(Configuration["ConnectionStrings:RestaurantDbConnection"]));
91
92 services.AddCors();
93 services.AddMvc();
94 }
95
96 // ezen nem hiszem hogy kell valtoztatnod, de majd hasonlitsd ossze a tieddel
97 public void Configure(IApplicationBuilder app, IHostingEnvironment env)
98 {
99 if (env.IsDevelopment())
100 {
101 app.UseDeveloperExceptionPage();
102 }
103 else
104 {
105 app.UseHsts();
106 }
107
108 app.UseCors(x => x
109 .AllowAnyOrigin()
110 .AllowAnyMethod()
111 .AllowAnyHeader());
112
113 app.UseHttpsRedirection();
114 app.UseAuthentication();
115 app.UseMvc();
116 }
117 }
118
119 // ez az osztaly generalja a jwt tokent. azert valosit meg sajat interface-t, mert a Startup osztalyban DI-nel ez alapjan tudja injektalni a fuggoseget.
120 // a GenerateToken fv.-nek parameterben adni kell egy string-et, ami minden felhasznalonak egyedi (pl user email)
121 // ez alapjan general egy token-t aminek a tulajdonosat beazonositja email cim alapjan a .net core (ha jol ertem, legyen hogy igy jo XD)
122 public class JwtTokenGeneratorService : ITokenGeneratorService
123 {
124 private AppSettings _appSettings;
125 public int TokenTimeInMinutes { get; } = 30;
126
127 public JwtTokenGeneratorService(IOptions<AppSettings> appSettings)
128 {
129 _appSettings = appSettings.Value;
130 }
131
132 public string GenerateToken(string tokenId)
133 {
134 var tokenHandler = new JwtSecurityTokenHandler();
135 var key = Encoding.ASCII.GetBytes(_appSettings.SecretKey);
136 var tokenDescriptor = new SecurityTokenDescriptor
137 {
138 Subject = new ClaimsIdentity(new Claim[]
139 {
140 new Claim(ClaimTypes.Name, tokenId)
141 }),
142 Expires = DateTime.UtcNow.AddMinutes(TokenTimeInMinutes),
143 SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key),
144 SecurityAlgorithms.HmacSha256Signature)
145 };
146
147 var token = tokenHandler.CreateToken(tokenDescriptor);
148 return tokenHandler.WriteToken(token);
149 }
150 }
151
152 // kell egy AuthenticatoinService, aminek ez lesz az interface-e (szinten a DI miatt)
153 public interface IAuthenticationService
154 {
155 Task<Users> Authenticate(IHeaderDictionary headers);
156 }
157
158 // ezzel a service-szel kell vegezni az autentikalast.
159 // az Authenticate metodusnak at kell adni a kerelem Header-jet, amiben bennevan az email es a password
160 public class AuthenticationService : IAuthenticationService
161 {
162 private IUsersRepository _usersRepository;
163
164 public AuthenticationService(IUsersRepository usersRepository)
165 {
166 _usersRepository = usersRepository;
167 }
168
169 public async Task<Users> Authenticate(IHeaderDictionary headers)
170 {
171 string email;
172 string password;
173
174 try
175 {
176 email = headers["email"];
177 password = headers["password"];
178 }
179 catch (Exception e)
180 {
181 Console.WriteLine(e.StackTrace);
182 return null;
183 }
184
185 // ezen a ponton kiolvastad az email és a password valtozoba az authentikacios adatokat.
186 // itt elvegzed a sajat validalasodat, majd SELECT-eled a User rekordot és visszaadod a User objektumot.
187 // ha null-t ad vissza, akkor sikertelen az autentikalas. ez nem a legjobb megoldas, de faszom fogja atirni
188
189 return user;
190 }
191 }
192
193
194// Ennek az egesz ratyinak a hasznalata:
195
196 // tetszoleges Controller osztalyba hozzaadod pl ezt a vegpontot.
197 // a kerelemhez hozza lehet csatolni "Bearer Token" tipusu "Authnorization"-t. ott egy string-kent hozza lehet csatolni a jwt tokent a kesobbiekben, ami utan bejelentkezett a felhasznalo.
198 // Header-be 2 db kulcs-ertek part kell megadni: az email(kulcs: "email") es a password (kulcs: "password")
199 [HttpGet("Login")]
200 public async Task<IActionResult> Login()
201 {
202 // az _authenticationService-t konstruktoron keresztul tudod injektalni adatmezobe
203 // a beerkezo kerelem Header-jet atadod parameterben.
204 // ha gondolod ird at, hogy csak email-t es pw-t fogadjon, talan ugy szebb
205 var user = await _authenticationService.Authenticate(HttpContext.Request.Headers);
206
207 // ha a user null, akkor nem sikerult autentikalni, return 401-es kod
208 if (user == null)
209 {
210 return Unauthorized();
211 }
212
213 // ha nem null a user, akkor generalunk neki egy JWT tokent, elmentjuk db-be (bar ez folosleges)
214 // es visszaadjuk az autnetikalt user-t.
215 // ilyenkor mar az API autnetikaltnak ertelmezi a felhasznalot
216 user.Token = _tokenGeneratorService.GenerateToken(user.Email);
217 await _usersRepository.UpdateAsync(user);
218
219 return Ok(user);
220 }