Add Token to webrequests
Wenn man mit Authorisierung in webanwendungen arbeitet, muss man einen Token in den Header einer Web-Anfrage einfügen.
Dieser enthält die verschlüsselten Informationen zum aktuellen User und ist somit eine Zugriffskontrolle.
In Angular wird der Vorgang mit einem Intercept durchgeführt.
Services/authentication.service.ts
import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from "@angular/common/http"; import { Injectable } from "@angular/core"; import { Observable } from "rxjs"; import { CookieService } from 'ngx-cookie-service' //*for using cookies
@Injectable() export class AuthenticationInterceptor implements HttpInterceptor { //</ init > constructor(private cookieService: CookieService) { } //</ init >
//* on any authorize-error 401, add the token to the header intercept( request: HttpRequest<any>, next: HttpHandler, //err:HttpErrorResponse ): Observable<HttpEvent<any>> { //better check for URL to api-data urls const url: string = request.url.toLocaleLowerCase(); if (url.indexOf("/api/") > 0) { //----< if request to api data-backend >---- var token = this.cookieService.get("t"); if (token) { request = request.clone({ //add the jwt token to the header setHeaders: { Authorization: `Bearer ${token}` }, //*token contains userid internal,encrypted }); } //----</ if request to api data-backend >---- }
return next.handle(request); } } |
Add to each outgoing data request the access token into the header.
Therefore only check, if the webrequest goes to /api/
Zusätzlich zum verarbeiten der Authentifizierungen kann die authentication.service.ts verwendet werden
Services/authentication.ts
import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Injectable,OnInit } from '@angular/core'; import { BehaviorSubject, map, Observable } from 'rxjs'; import { environment } from 'src/environments/environment'; import { User_Model } from '../models/usermodel'; import { CookieService } from 'ngx-cookie-service' //*for using cookies import { Router } from '@angular/router';
const url_Api_Auth = environment.apiUrl + "/Authentication"; const httpOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/json' })};
@Injectable({ providedIn: 'root' }) export class AuthenticationService implements OnInit{ //--------< AuthenticationService >-------- //*opens webapi and gets data private userSubject: BehaviorSubject<User_Model | null>; public user: Observable<User_Model | null>; public token:string=""; constructor(private http: HttpClient, private cookieService: CookieService, private router:Router) { this.userSubject = new BehaviorSubject(JSON.parse(localStorage.getItem('u')!)); this.user = this.userSubject.asObservable(); } //*inject web-api caller
ngOnInit() { //this.email = localStorage.getItem('e')!; this.token = this.cookieService.get("t")!; }
//try to register and send result true/false //test: public async register(username:string, email:string, password:string):Promise<boolean> { public register(username:string, email:string, password:string) { //--------< register() >-------- //*try to /register with email password and get token as result. return this.http.post<any>(url_Api_Auth + "/register",{Username:username,Email:email,Password:password}) .subscribe( { next: (response_username_token:any ) => { //*store token in local storage var token=response_username_token.token; var username=response_username_token.username;
this.cookieService.set('t', token,365); this.token=token; localStorage.setItem('u',JSON.stringify(username)) this.userSubject.next(username); console.log("register ok"); this.router.navigate(['/home']);
return true; //->total result is true for the wrapping function } ,error: (e) => { console.log("/register.error:" + e.message); alert(e.message); return false; //->total result is true for the wrapping function } ,complete: () => console.log('register complete') }); //--------</ register() >-------- }
//try to register and send result true/false public async login(email:string, password:string):Promise<boolean> { //*try to /register with email password and get token as result. //if token is ok, then true else false const webrequest=await this.http.post<any>(url_Api_Auth + "/login",{email,password}); webrequest.subscribe( { next: (token: string) => { //*store token in local storage this.cookieService.set("t", token,365); this.token=token; console.log("login ok"); this.router.navigate(['/home']); return true; } ,error: (e) => { console.log("/login.error:"+ e.message); alert(e.message); return false; } ,complete: () => console.log('register complete') });
if (this.token!="") return true; else return false; }
public logout(){ localStorage.clear(); this.cookieService.deleteAll(); this.token=""; this.user.pipe(map(u=>{ u!.username="x";})) }
public getMe(): Observable<string> { return this.http.get( url_Api_Auth + "/getme", { responseType: 'text' } ) } }
|
Zuletzt muss der Interceptor in der app.module.ts eingefügt werden
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; //*for url to web-api import { AppRoutingModule } from './app-routing.module'; import { CookieService } from 'ngx-cookie-service';
import { AppComponent } from './app.component'; import { ListArticlesComponent } from './components/articles/list-articles/list-articles.component'; import { EditArticleComponent } from './components/articles/edit-article/edit-article.component'; import { ReadArticleComponent } from './components/articles/read-article/read-article.component'; import { FormsModule } from '@angular/forms'; import { UserComponent } from './components/user/user.component'; import { AuthenticationInterceptor } from './services/authentication.interceptor'; import { RegisterComponent } from './components/user/register/register.component'; import { LoginComponent } from './components/user/login/login.component';
@NgModule({ //*Insert Components in Declatation declarations: [ AppComponent, //*main page ListArticlesComponent, EditArticleComponent, ReadArticleComponent, UserComponent, RegisterComponent, LoginComponent, ], //*Insert Modules in Import imports: [ BrowserModule, AppRoutingModule, //*imports app-routing file HttpClientModule, //for web-api cll FormsModule ],
//*authenticate intercepter providers: [{ provide: HTTP_INTERCEPTORS, useClass:AuthenticationInterceptor, multi:true }, { provide: CookieService } ], bootstrap: [AppComponent] }) export class AppModule { }
|
BACKEND
In der Web-API kann der User dann ausgelesen werden:
Asp.net
Core API Backend
ArticlesController.cs
// GET: api/<ArticlesController> [HttpGet("get_list")] public async Task<ActionResult<List<ArticleDbModel>>>Get_List() { var userGUID = HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier);
//load top 10 //var query = from t in _dbContext.tbl_Articles orderby t.IDArticle descending select t; var query = from t in _dbContext.tbl_Articles orderby t.IDArticle descending select new { idarticle=t.IDArticle, title =t.Title }; var list_Articles=query.Take(10); var output_list = await list_Articles.ToListAsync(); //return list_Artcles.ToList(); return Ok(output_list); //👍 better loading } |
Hierzu muss die Authorisierung mit Java JWT tokens in der App eingefügt werden
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.Filters; using System.Text; using Services; using webapp_codedocu.Data;
#region //==< Builder.Configure >== //==< Builder >== var builder = WebApplication.CreateBuilder(args); // Add services to the container.
//< get_config > string config_App_SignInKey = builder.Configuration.GetSection("AppSettings").GetValue<String>("App_SignInKey") ?? throw new InvalidOperationException("AppSignInKey missing in Config.AppSettings");
string url_FrontEnd = builder.Configuration.GetSection("AppSettings").GetValue<String>("Url_FrontEnd") ?? throw new InvalidOperationException("UrlFrontEnd is missing in Config.AppSettings");
string connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string not found in Config");
//</ get_config >
//* Connect Database builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(connectionString));
builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer();
builder.Services.AddScoped<IUserService, UserService>(); builder.Services.AddHttpContextAccessor();
//builder.Services.AddSwaggerGen(); builder.Services.AddSwaggerGen(options => { options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme { Description = "Standard Authorization header using the Bearer scheme (\"bearer {token}\")", In = ParameterLocation.Header, Name = "Authorization", Type = SecuritySchemeType.ApiKey });
options.OperationFilter<SecurityRequirementsOperationFilter>(); //by Swashbuckle }); builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) //by Microsoft.AspCore.Authentication .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config_App_SignInKey)), //*Decode AccessToken by App-Key ValidateIssuer = false, ValidateAudience = false }; });
//< CORS > //*allow calls from AngularUI builder.Services.AddCors(options => options.AddPolicy(name: "FrontendUI", policy => { policy.WithOrigins(url_FrontEnd).AllowAnyMethod().AllowAnyHeader(); })); //</ CORS >
//==</ Builder >== #endregion //==</ Builder.Configure >==
#region //==< APP >== //==< APP >== var app = builder.Build();
// Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); }
//< CORS > app.UseCors("FrontendUI"); //</ CORS >
app.UseHttpsRedirection();
app.UseAuthentication(); //*Get User app.UseAuthorization();
app.MapControllers();
app.Run(); //==</ APP >== #endregion //==</ APP >== |