I'm working on an Android app based on Clean Architecture pattern and I have doubts how to implement user authentication in a clean way. Is the following solution clean in terms of clean architecture?
I would create use cases like below (executed from presentation layer):
LoginUseCase (for provided login and password fetches api token via remote service and saves in local token source)
LogoutUseCase (clears token from LocalTokenSource)
(LocalTokenSource interface would be stored in domain layer and its implementation in data layer - kind of repository)
And in order to perform token refresh at each app launch (it's not a use case from the user perspective, right?) I would create SessionManager component in domain layer. SessionManager would be responsible for refreshing token and saving it in LocalTokenSource. Each time activity is started, from its presenter I would execute refreshToken() on injected SessionManager. What do you think about the solution?
If it's clean, then how to handle passing token to the remote service to execute other API methods which require token? Lets say I have PostsRepository which fetches posts data from remote service. Should I pass token from a use case to the repository method like repo.getPosts(token)? Or inject LocalTokenSource to the repository, so it could read the token on its own? Wouldn't the second option violate Clean Architecture rules, because LocalTokenSource would be used in 2 layers?
The central question you would have to decide is: Do you want to model authorization (and so the usage of the token) as an aspect of your business logic OR do you want to consider it as an "implementation detail".
If you decide for the first, having dedicated use cases for it, adding the SessionManager to the domain layer and passing the token to the repositories would be a consistent modeling.
If you decide for the later, login/logout/refresh as well as the existence of the token is probably best kept "behind the scenes", so in the framework or gateway layer.
Both approaches would follow the rules of the Clean Architecture (as long as you do not violate the dependency rule).
Related
I've been searching for a clean, reliable way to persist the current user in an Android app, which is accessible from any activity/view, is available immediately, and can be reliably cleared upon logout.
To add further context, the app handles API authentication via a token (JWT). Unfortunately there is no user info in the payload.
There is an MVVM architecture, and there is a Repository layer, which calls a retrofit api/room db.
Here are the things I'm exploring, would love to know if any are any better ways to go, or if there's another pattern/architecture I've not discovered yet:
Presently a User object is persisted on the Application class. I hate this personally, it's what existed previously. Upon successful login, the JWT is stored in SharedPreferences, and the User object is saved as a static variable in the Application class.
Immediately there is the thought to at least store the important bits of the user in SharedPreferences too. I was trying to find someway to "bundle" the user with the JWT, sharedpreferences doesn't really play nicely with objects though. I imagine a scenario where I may have a stored token for one user, but the User object for another, which will cause all sorts of problems.
As well as our retrofit API service layer, there is a basic Room db spun up as I slowly try to incorporate local caching throughout the app. So I know I can persist the User here, although worried about the async nature of DB calls.
I feel what I'm after is some kind of architectural layer, a SesssionManager or something, that takes care of all of this. Will "hold" the User, the Token, have a global Logout() method, will somehow play nicely with the repository layer, so the View and ViewModels don't really need to bother with the user or userId at all, just make the various repository calls, and the data (repository/retrofit service) layers will return what is right for the currently logged in user etc.
Sorry if this is a bit abstract/high level without any specific code, I just remember finding months ago an excellent article to do with this notion of a Session layer, and didn't bookmark it and now am scratching my head trying to work out the best way to achieve this cleanly.
How should authentication be implemented to fit in the Clean Architecture pattern?
Say I need a token (oauth, googleapi, I see you) for some of my API requests. How should I get this token from my login screen and User Repository to my RandomDataRepository for example?
It seems strange to put that in each of my RandomData Use Cases, and strange too to have my remote RandomData layer talking to another Repository module.
Should the token be passed for every request (kinda ugly if my repository can switch from cache / remote), or should it be injected once and referenced somewhere, like in an interceptor?
I found this but I don't understand the login worfklow and there's no full code)
Thanks !
I am following clean architecture, and I understand the use of the repository for actions like getUsers or queryUsers. However does not make sense to me the use of a repository to login a user. How should I communicate with the Data Layer then, should I skip the repository layer and access the network layer?
I definitely think that you should not skip layers.
The whole point of introducing a certain architecture is to follow it without exception, so all your app modules behave in an expected and predictable way.
So, if you look at it from a different angle, what does logging in mean? You get a username and a password and you must check if they match a username and a password that are stored in your datasource. To do this, you run a query against your current users. And queries are run where - in the repository! You said it yourself - the repository is where all querying should happen. What is implementation behind it is of no importance.
So, my suggestion is to add a method like this one:
public interface UserRepository {
User findByUsernameAndPassword(#NonNull String username, #NonNull String
password);
}
If you manage to find a user - good, he's authenticated, if not - sorry, try again.
from this guid i think using repository is a better choice. my answer based on the definition of the repository quoting :
Repository modules are responsible for handling data operations.
I believe in clean architecture you should not skip layers. I see a few options here:
userRepository.get\set-User() - for me, it looks a bit weird because Repository is an abstraction over collection while we need only one.
create an abstraction over user storage. For example, userStorage.get\set-User() or userStorage.login(User), logout(), get()
For android MVVM architecture, in all the examples that I have seen, people either use Room to store/retrieve data or they get data directly from API calls through the Repository class.
I'm neither doing an API call nor using I have Room database to store data. But I need my ViewModel to get the data from the repository and pass it to my Actvity.
Can your Repository class inherit from Application class so that you can save static variables/companion objects if you don't intend to use Room for saving data locally ?
What is a good way to handle this case?
In general, in Software Engineering a Repository is used to abstract the Data Layer (Database, Web Service) from the rest of the application (usually directly Business Tier), a good example would be this schema of a booking website:
It receives the updates via the Publish/Subscribe asynchronous connection and sends them to the other components. So the components are independent of each other.
So Repository is just a simple mediator class that is used to make the application more modular, so that you can swap out pieces easier, and make sure that the rest of the app doesn't bother with DB connections or HTTP calls and so on. So technically, you can inherit from Application (or anything else) and use it to save static variables and so on.
But as explained here:
The application object is not guaranteed to stay in memory forever, it will get killed. Contrary to popular belief, the app won’t be restarted from scratch. Android will create a new Application object and start the activity where the user was before to give the illusion that the application was never killed in the first place.
So it's entirely up to you, you can use the repository style as you wish, it's not at all tied to Room or anything else.
I'm trying to use Uncle Bob's clean architecture in my android app. So, I followed this guy's great implementation based on RxAndroid, Dagger 2 for DI. I know that to get data from data stores (Cloud or local db or disk), the Interactors (Use Case classes in the Domain layer) will invoke Repositories in the DATA Layer.
In my case, I have to execute two parallel REST API calls (Foursquare API and Google places API), then, compare the received data from each call.
Do I have to put these Retrofit calls' implementation in the Data layer or inside the Interactors in the Domain layer ? If any external API call belongs to the data layer, what's exactly the role of interactors in Uncle Bob's approach ?
I'm new to this approach, any help is greatly appreciated!
i think you should call the API in data layer and then process the result in domain layer, of course if the result was independent from any framework.
and interactors was the one that orchestrate the flow of data to and from the entities. (http://fernandocejas.com/2014/09/03/architecting-android-the-clean-way/)