Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deprecate mixins #2198

Merged
merged 20 commits into from
Jun 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ jobs:
matrix:
workspace:
- ember-simple-auth
- classic-test-app
- test-app

steps:
Expand Down Expand Up @@ -51,6 +52,7 @@ jobs:
matrix:
workspace:
- ember-simple-auth
- classic-test-app
- test-app
test-suite:
- test:one ember-3.0
Expand Down Expand Up @@ -96,6 +98,7 @@ jobs:
matrix:
workspace:
- ember-simple-auth
- classic-test-app
- test-app

steps:
Expand Down
133 changes: 69 additions & 64 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,10 @@ etc.
## Example App

__Ember Simple Auth comes with a
[dummy app](tests/dummy)
[test app](packages/test-app/)
that implements a complete auth solution__ including authentication against
the application's own server as well as Facebook, authorization of Ember Data
requests and error handling. __Check out that dummy app for reference.__ To
requests and error handling. __Check out that test app for reference.__ To
start it, run

```
Expand All @@ -103,15 +103,16 @@ ember install ember-simple-auth
```

### Upgrading from a pre-3.0 release?
The 3.0 release of ember-simple-auth removes previously deprecated code, introducing some breaking changes,
but thankfully there is an [upgrade guide](guides/upgrade-to-v3.md).
The 3.0 release of ember-simple-auth removes previously deprecated code,
introducing some breaking changes, but thankfully there is an
[upgrade guide](guides/upgrade-to-v3.md).

## Walkthrough

Once the library is installed, __the session service can be injected wherever
needed in the application__. In order to display login/logout buttons
depending on the current session state, inject the service into the respective
controller or component and __query its
needed in the application__. In order to display login/logout buttons depending
on the current session state, inject the service into the respective controller
or component and __query its
[`isAuthenticated` property](http://ember-simple-auth.com/api/classes/SessionService.html#property_isAuthenticated)
in the template__:

Expand Down Expand Up @@ -224,45 +225,23 @@ export default class LoginController extends Controller {
}
```

__The session service also provides the
[`authenticationSucceeded`](http://ember-simple-auth.com/api/classes/SessionService.html#event_authenticationSucceeded)
and
[`invalidationSucceeded`](http://ember-simple-auth.com/api/classes/SessionService.html#event_invalidationSucceeded)
events__ that are triggered whenever the session is successfully authenticated
or invalidated (which not only happens when the user submits the login form or
clicks the logout button but also when the session is authenticated or
invalidated in another tab or window of the application). __To have these
events handled automatically, simply mix
[`ApplicationRouteMixin`](http://ember-simple-auth.com/api/classes/ApplicationRouteMixin.html)
into the application route__:

```js
// app/routes/application.js
import Route from '@ember/routing/route';
import ApplicationRouteMixin from 'ember-simple-auth/mixins/application-route-mixin';

export default class ApplicationRoute extends Route.extend(ApplicationRouteMixin) {}
```

The `ApplicationRouteMixin` automatically maps the session events to the
[`sessionAuthenticated`](http://ember-simple-auth.com/api/classes/ApplicationRouteMixin.html#method_sessionAuthenticated)
and
[`sessionInvalidated`](http://ember-simple-auth.com/api/classes/ApplicationRouteMixin.html#method_sessionInvalidated)
methods it implements. The `sessionAuthenticated` method will transition to a
configurable route while the `sessionInvalidated` method will reload the page
to clear all potentially sensitive data from memory.

__To make a route in the application accessible only when the session is
authenticated__, mix the
[`AuthenticatedRouteMixin`](http://ember-simple-auth.com/api/classes/AuthenticatedRouteMixin.html)
into the respective route:
authenticated__, call the session service's
[`method_requireAuthentication`](http://ember-simple-auth.com/api/classes/SessionService.html#method_requireAuthentication)
method in the respective route's `beforeModel` method:

```js
// app/routes/protected.js
// app/routes/authenticated.js
import Route from '@ember/routing/route';
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
import { inject as service } from '@ember/service';

export default class AuthenticatedRoute extends Route {
@service session;

export default class ProtectedRoute extends Route.extend(AuthenticatedRouteMixin) {}
beforeModel(transition) {
this.get('session').requireAuthentication(transition, 'login');
},
}
```

This will make the route (and all of its subroutes) transition to the `login`
Expand All @@ -276,10 +255,6 @@ Router.map(function() {
});
```

The route to transition to if the session is not authenticated can also be
[overridden](https://ember-simple-auth.com/api/classes/AuthenticatedRouteMixin.html#property_authenticationRoute)
to be another one than `login`.

It is recommended to nest all of an application's routes that require the
session to be authenticated under a common parent route:

Expand All @@ -294,24 +269,52 @@ Router.map(function() {
```

To prevent a route from being accessed when the session is authenticated (which
makes sense for login and registration routes for example), mix the
[`UnauthenticatedRouteMixin`](http://ember-simple-auth.com/api/classes/UnauthenticatedRouteMixin.html)
into the respective route.
makes sense for login and registration routes for example), call the session
service's
[`prohibitAuthentication`](http://ember-simple-auth.com/api/classes/SessionService.html#method_prohibitAuthentication)
method in the respective route's `beforeModel` method:

In order to add authorization information to requests, you can use the session service
to check if the session is authenticated and access authentication/authorization data, e.g. a token.
```js
// app/routes/login.js
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';

export default class LoginRoute extends Route {
@service session;

beforeModel(transition) {
this.get('session').prohibitAuthentication('index');
},
}
```

We provide the `DataAdapterMixin` for Ember Data adapters, that injects the session service
and also makes sure the session is invalidated if any of the requests returns an unauthorized response.
It can be used as:
__The session service also provides the
[`handleAuthentication`](http://ember-simple-auth.com/api/classes/SessionService.html#method_handleAuthentication)
and
[`handleInvalidation`](http://ember-simple-auth.com/api/classes/SessionService.html#method_handleInvalidation)
methods__ for handling authentication and invalidation of the session (which
not only happens when the user submits the login form or clicks the logout
button but also when the session is authenticated or invalidated in another tab
or window of the application). The `handleAuthentication` method will
transition to a configurable route while the `handleInvalidation` method will
reload the page to clear all potentially sensitive data from memory. In order
to customize those behaviours, these methods can be overridden when the
application defines its own session service that extends the one provided by
Ember Simple Auth.

To add authorization information to requests, you can use the session service
to check if the session is authenticated and access
authentication/authorization data, e.g. a token:

```js
// app/adapters/application.js
import JSONAPIAdapter from '@ember-data/adapter/json-api';
import DataAdapterMixin from 'ember-simple-auth/mixins/data-adapter-mixin';
import { computed } from '@ember/object';
import { inject as service } from '@ember/service';

export default class ApplicationAdapter extends JSONAPIAdapter {
@service session;

export default class ApplicationAdapter extends JSONAPIAdapter.extend(DataAdapterMixin) {
@computed('session.data.authenticated.access_token')
get headers() {
let headers = {};
Expand Down Expand Up @@ -593,21 +596,23 @@ The session can then be authenticated or invalidated from the host app or any
of the engines and the state will be synchronized via the service.

One thing to be aware of is that if the authentication route is outside of the
engine (e.g. in the host app), it is necessary to override the
`triggerAuthentication` method of the `AuthenticatedRouteMixin` inside of the
engine as that needs to transition to an **external** route in that case:
engine (e.g. in the host app), it is necessary to use the special
`transitionToExternal` method in the engine to transition to it. That can be
done by passing a callback instead of a route name to the session service's
`requireAuthentication` method in that case:

```
// my-engine/addon/routes/index.js
import Route from '@ember/routing/route';
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
import { inject as service } from '@ember/service';

export default class IndexRoute extends Route.extend(AuthenticatedRouteMixin) {
triggerAuthentication() {
this.transitionToExternal('login');
}
}
export default class IndexRoute extends Route {
@service session;

beforeModel(transition) {
this.get('session').requireAuthentication(transition, () => this.transitionToExternal('login'));
},
}
marcoow marked this conversation as resolved.
Show resolved Hide resolved
```

## Testing
Expand Down
50 changes: 21 additions & 29 deletions guides/auth-torii-with-github.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,41 +250,32 @@ When you spin up the server again with `ember serve`, you should see, at

### Adding Authentication

First, we'll add the [ApplicationRouteMixin](http://ember-simple-auth.com/api/classes/ApplicationRouteMixin.html) to
our application route. This is optional, but adds methods supporting the authentication lifecycle that we would
otherwise have to implement explicitly.

```js
// app/routes/application.js

import Route from '@ember/routing';
import ApplicationRouteMixin from 'ember-simple-auth/mixins/application-route-mixin';

export default class ApplicationRoute extends Route.extend(ApplicationRouteMixin) {
}
```

Next, we'll designate the `index` route as an authenticated route using the
[AuthenticatedRouteMixin](http://ember-simple-auth.com/api/classes/AuthenticatedRouteMixin.html). This will make the
route inaccessible until we finish the authentication. It will automatically redirect you to the specified login route,
by default `login`, if you are not authenticated.
First, we'll designate the `index` route as an authenticated route using the
session service's
[requireAuthentication](http://ember-simple-auth.com/api/classes/SessionService.html#method_requireAuthentication)
method. This will make the route inaccessible until we finish the
authentication. It will automatically redirect you to the specified login
route, if you are not authenticated.

```js
// app/routes/index.js

import Route from '@ember/routing';
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
import { inject as service } from '@ember/service';

export default IndexRoute extends Route {
@service session;

export default IndexRoute extends Route.extend(AuthenticatedRouteMixin) {
beforeModel(transition) {
this.get('session').requireAuthentication(transition, 'login');
},
}
```

If you're still running the app when you save this, you will see it redirect to the `login` route.

We'll also designate the `login` route as available for unauthenticated access only by applying the
[UnauthenticatedRouteMixin](http://ember-simple-auth.com/api/classes/UnauthenticatedRouteMixin.html) to it. This will
redirect you to the `routeIfAlreadyAuthenticated` which defaults to `index`. As you can see, `ember-simple-auth` has
sensible and convenient defaults.
We'll also designate the `login` route as available for unauthenticated access only by calling the session service's
[prohibitAuthentication](http://ember-simple-auth.com/api/classes/SessionService.html#method_prohibitAuthentication).
This will redirect you to the `index` route.

Next, we'll create and set up our torii authenticator to start.

Expand Down Expand Up @@ -680,9 +671,11 @@ ember g adapter github-user

import { computed } from '@ember/object';
import GitHubUserAdapter from 'ember-data-github/adapters/github-user';
import DataAdapterMixin from "ember-simple-auth/mixins/data-adapter-mixin";
import { inject as service } from '@ember/service';

export default class GithubUserAdapter extends GitHubUserAdapter {
@service session;

export default class GithubUserAdapter extends GitHubUserAdapter.extend(DataAdapterMixin) {
@computed("session.data.authenticated.access_token")
get headers() {
const headers = {};
Expand All @@ -697,8 +690,7 @@ export default class GithubUserAdapter extends GitHubUserAdapter.extend(DataAdap
}
```

This adapter injects an authorization header into the GitHub request now. The `DataAdapterMixin` is a mixin provided by
`ember-simple-auth` that injects the `session` service we use to generate the authentication header.
This adapter injects an authorization header into the GitHub request now.

### Wrapping Up

Expand Down
42 changes: 28 additions & 14 deletions guides/managing-current-user.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,33 +126,22 @@ The Ember Simple Auth session can either be authenticated already when the
application starts up or become authenticated later when either the user logs
in via that instance of the application or the session state is synced from
another tab or window. In the first case, the session will already be
authenticated when the application route's `beforeModel` method is called and
in the latter case Ember Simple Auth will call the application route's
`sessionAuthenticated` method. The `currentUser` service's `load` method must
be called in both cases so that it's `user` property is always populated when
the session is authenticated:
authenticated when the application route's `beforeModel` method is called:

```js
// app/routes/application.js

import Route from '@ember/routing/route';
import ApplicationRouteMixin from 'ember-simple-auth/mixins/application-route-mixin';

import { inject as service } from '@ember/service';

export default class ApplicationRoute extends Route.extend(ApplicationRouteMixin) {
export default class ApplicationRoute extends Route {
@service session;
@service currentUser;

beforeModel() {
return this._loadCurrentUser();
},

async sessionAuthenticated() {
let _super = this._super;
await this._loadCurrentUser();
_super.call(this, ...arguments);
},

async _loadCurrentUser() {
try {
await this.currentUser.load();
Expand All @@ -162,3 +151,28 @@ export default class ApplicationRoute extends Route.extend(ApplicationRouteMixin
}
});
```

In the latter case Ember Simple Auth will call the session service's
`handleAuthentication` method. The `currentUser` service's `load` method must
be called in that cases as well. We can do that by overriding the session
sevice's method in a custom extension of Ember Simple Auth's standard session
service:

```js
import { inject as service } from '@ember/service';
import SessionService from 'ember-simple-auth/services/session';

export default SessionService.extend({
@service currentUser;
marcoow marked this conversation as resolved.
Show resolved Hide resolved

async handleAuthentication() {
this._super(...arguments);

try {
await this.currentUser.load();
} catch(err) {
await this.invalidate();
}
}
});
```
Loading