Authentication and Authorization in DDD

Use Case example

  • Author: existing user in the next blogging platform. It is Entity with unique identifier of authorId;
  • Blog: specific area of blogging platform containing posts. It is Entity with unique identifier of blogId;
  • Collaborator: Author who can create the posts to the given blog;
  • Authentication: process to identify the Author.
  • Authorization: process to check if the Author is Collaborator in the given Blog.

Version 1: Authentication/Authorization outside Application Services

// Request
class AddPostRequest()
{
public function authorId() {…}
public function blogId() {…}
public function title() {…}
public function text() {…}
}
// Application Service
class AddPostService()
{
public function execute($request)
{
$authorId = $request->authorId();
$blogId = $request->blogId();
$title = $request->title();
$text = $request->text();
if (!$blog = $this->blogRepository->blogOfId($blogId)) {
throw new BlogNotFoundException();
}

$post = $blog->buildPost(
$this->postRepository->nextIdentity(),
$authorId,
$title,
$text
);
$this->postRepository->save($post);
}
}

class PostController
{
public newPostAction()
{
if (!$this->sessionService()->isAuthenticated()) {
throw new UnauthenticatedUserException();
}
$blogId = $this->request->get(‘blog_id’);
$userId = $this->sessionService()->currentUserId();

$isCollaborator = $this->permissionService()->isCollaborator(
$userId, $blogId
);
if (!$isCollaborator) {
throw new UnauthorizedUserException();
}
// executes AddPostService use case
}
}
class PostRestFulController
{
public newPostAction()
{
$authorizationValue = $this->authorizationHeader();
$userId = $this->oauthService()->userId($authorizationValue);
$blogId = $this->request->get(‘blog_id’);
if (!$userId) {
throw new UnauthenticatedUserException();
}
$isCollaborator = $this->permissionService()->isCollaborator(
$userId, $blogId
);
if (!$isCollaborator) {
throw new UnauthorizedUserException();
}
// execute AddPostService use case
}
}
> blog add-post — user-id 1 — blog-id 1 — title Foo …class PostConsole
{
public newPostCommand()
{
// gets values from console parameters
// execute AddPostService use case
}
}
  • Authentication/Authorization is checked outside from ApplicationService in the Controller (or in a hook in the framework).
  • Authentication/Authorization must be executed before ApplicationService use case.
  • Depending on entry point of the application an authentication service is uses. In the example OAuthService, SessionService.

Version 2: Authentication/Authorization within Application Services

interface CollaboratorService
{
public function authorFrom($authorId, $blogId);
}
// Request
class AddPostRequest
{
public function authorId() {…}
public function blogId() {…}
public function title() {…}
public function text() {…}
}
// Application Service
class AddPostService
{
public function execute($request)
{
$authorId = $request->authorId();
$blogId = $request->blogId();
$title = $request->title();
$text = $request->text();
$author = $this->collaboratorService->authorFrom(
$authorId,
$blogId
);
if (!$author) {
throw new InvalidAuthorException();
}
if (!$blog = $this->blogRepository->blogOfId($blogId)) {
throw new BlogNotFoundException();
}

$post = $blog->buildPost(
$this->postRepository->nextIdentity(),
$author,
$title,
$text
);

$this->postRepository->save($post);
}
}
class UserIdCollaboratorService implements CollaboratorService
{
public function authorFrom($authorId, $blogId) { … }
}
class PostController
{
public newPostAction()
{
$authorId = $this->sessionService()->userId();
// executes ApplicationService use case
}
}
class OAuthCollaboratorService implements CollaboratorService
{
public function authorFrom($authorId, $blogId) { … }
}
class PostRestFulController
{
public newPostAction()
{
$authorId = $this->authorizationHeader();
// executes ApplicationService use case
}
}
blog add-post — author-id 1 — blog-id 1 — title Foo
class ConsoleCollaboratorService implements CollaboratorService
{
public function authorFrom($authorId, $blogId) { … }
}
class PostConsole
{
public newPostCommand()
{
// gets values from console parameters
// executes AddPostService use case
}
}
  • All checks of authentication/authorization are within the ApplicationService implicitly used in CollaboratorService.
  • The input parameter in authorId in AddPostService is somehow polymorphic, due accepts tokens from REST or direct id value from Web. Maybe this is the key that allow us to put authentication/authorization within ApplicationService.
  • CollaboratorService needs several implementation depending on authentication mechanism.

Changelog

  • 2016–01–08: added Ubiquitous Language description. Thanks to @robegrei

--

--

--

Software Engineer with true passion for creating clean, functional and well-designed code.

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
José Luis Martínez de la

José Luis Martínez de la

Software Engineer with true passion for creating clean, functional and well-designed code.

More from Medium

How to Use AWS Parameter Store

How to Deploy SpringBoot App to Elastic Beanstalk Using Github Actions CI/CD

Spring Boot Microservices — Part1 — Eureka Discivery Service

How to test the integration between Google Cloud Storage and Spring Boot using Testcontainers