- Wiederholung High Level Flow (Beziehung ID Provider - Client - Resource Server) (Präsentation zeigen)
- [Backend und Frontend gestartet] Login durchführen. In der Frontend Log-Datei (Filter auf ApiFactory und MainActivity) das Access Token, Expiration Time und die zurückgegebenen User-Daten zeigen.
- Access Token Inhalt in https://jwt.io (zeigen) (die Expiry Time könnte man noch bei https://www.epochconverter.com/ dekodieren)
- Backend: WebSecurityConfig zeigen --> hier ist die abgesicherte Route festgelegt;
Resource Server Konfigurations-Details im JwtDecoder (keine weitere Erklärung). Authentication relevante Klassen im Package authentication (aufklappen).
- Frontend: ApiFactory zeigen --> Zufügung des Authentication Headers über den Authenticator (keine weitere Erklärung)
- Zum Einschalten des abgesicherten Zugriffs: im Frontend, UserProfileApi, im ersten @Get()
secure/
einfügen:
public interface UserProfileApi {
@GET("secure/api/v1/profiles/{id}")
LiveData<ApiResponse<UserProfile>> getById(@Path("id") Long id);
@GET("/api/v1/profiles/{providerUserId}/provideruserid")
LiveData<ApiResponse<UserProfile>> getByProviderUserId(@Path("providerUserId") String providerUserId);
@POST("/api/v1/profiles")
LiveData<ApiResponse<UserProfile>> updateUserProfile(@Body UserProfile newProfile);
@PATCH("/api/v1/profiles/{id}")
LiveData<ApiResponse<UserLoginProfile>> patchUserLogin(@Path("id") Long id, @Body UserLoginProfile userLoginProfile);
}
- Weiter im Backend: Die Klasse SecureUserProfileRestController im authentication package löschen (war nur zur Demo - sonst gibt es später Controller Konflikte)
- Im package profile/rest die Route in der Klasse UserProfileRestController um
secure/
erweitern: @RequestMapping("secure/api/v1/profiles")
.
- Vorführen, dass der Zugriff vom Frontend aus (GET-Button auf der User Profile Seite) mit diesen beiden Änderungen funktioniert. Im Frontend log kann man die geänderte Route sehen und dass der TokenAuthenticator ein Token abruft.
UserProfileRestController.getById()
: Falls eine Prüfung des abfragenden Users im Backend erforderlich ist, um Datensichtbarkeit einzuschränken, muss man den @AuthenticationPrincipal()
einführen und die beiden Attribute Subject und Issuer abgleichen (den Code am besten kopieren, da es sonst viel Tipperei ist):
@GetMapping("{id}")
public UserProfile getById(@PathVariable("id") Long id, @AuthenticationPrincipal() Jwt authenticatedUserJwt) {
UserProfile userProfile = this.repo.findById(id).get(); // Quick and dirty - don't repeat at home!
if (authenticatedUserJwt.getSubject().equals(userProfile.getProviderUserId()) //<--"12345"
&& authenticatedUserJwt.getIssuer().toString().equals(userProfile.getIdProvider())) {
//*************************************************************
// Die nächsten drei Zeilen existieren bereits:
return this.repo.findById(id).orElseThrow(() -> {
throw new ResponseStatusException(HttpStatus.NOT_FOUND);
});
//*************************************************************
} else {
throw new ResponseStatusException(HttpStatus.FORBIDDEN);
}
}
- Vorführen: Auch so funktioniert der Zugriff vom Frontend (GET-Button) wie zuvor.
- An der oben mit
//<--"12345"
markierten Stelle userProfile.getProviderUserId()
durch einen willkürlichen String ersetzen --> Frontend-Zugriff schlägt fehl, HTTP-Fehler 403 im Log.