oidc-client
https://github.com/IdentityModel/oidc-client-js
npm install oidc-client --save
配置
- environment
openIdConnectSettings: {
authority: 'https://localhost:6001/',
client_id: 'blog-client',
redirect_uri: 'http://localhost:4200/signin-oidc',
scope: 'openid profile email restapi',
response_type: 'id_token token',
post_logout_redirect_uri: 'http://localhost:4200/',
automaticSilentRenew: true,
silent_redirect_uri: 'http://localhost:4200/redirect-silentrenew'
}
- 后端config
// SPA client using implicit flow +++++>>>>Angular
new Client
{
ClientId = "blog-client",
ClientName = "Blog Client",
ClientUri = "http://localhost:4200",
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
RequireConsent = false, //是否需要点击同意
AccessTokenLifetime=180, //有效期180s
RedirectUris =
{
"http://localhost:4200/signin-oidc",
"http://localhost:4200/redirect-silentrenew",
},
PostLogoutRedirectUris = { "http://localhost:4200/" },
AllowedCorsOrigins = { "http://localhost:4200" },
AllowedScopes = {
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
"restapi"
}
}
- 后端startup配置跨域
//配置跨域
services.AddCors(options =>
{
options.AddPolicy("AngularClient", policy =>
{
policy.WithOrigins("http://localhost:4200")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
app.UseCors();
- Angular创建service
export class OpenIdConnectService {
private userManager: UserManager = new UserManager(environment.openIdConnectSetting);
private currentUser: User;
userLoaded$ = new ReplaySubject<boolean>(1); // observerable rxjs
get userAvailable(): boolean {
return this.currentUser != null;
}
get user(): User {
return this.currentUser;
}
constructor() {
this.userManager.clearStaleState();
this.userManager.events.addUserLoaded(user => {
if (!environment.production) {
console.log('User loaded.', user);
}
this.currentUser = user;
this.userLoaded$.next(true); // 广播
});
this.userManager.events.addUserUnloaded((e) => {
if (!environment.production) {
console.log('User unloaded.');
}
this.currentUser = null;
this.userLoaded$.next(false);
});
}
triggerSignIn() {
this.userManager.signinRedirect().then(() => {
if (!environment.production) {
console.log('Redirction to signin triggered');
}
});
}
handleCallback() {
this.userManager.signinRedirectCallback().then(user => {
if (!environment.production) {
console.log('callback after signin handled.', user);
}
});
}
handleSilentCallback() {
this.userManager.signinSilentCallback().then(user => {
this.currentUser = user;
if (!environment.production) {
console.log('callback after silent signin handled.', user);
}
});
}
triggerSignOut() {
this.userManager.signoutRedirect().then(resp => {
if (!environment.production) {
console.log('redirection to sign out triggered', resp);
}
});
}
}
-
signin-oidc
component
export class SigninOidcComponent implements OnInit {
constructor(private openIdConnectService: OpenIdConnectService,
private router: Router) { }
ngOnInit() {
this.openIdConnectService.userLoaded$.subscribe((userLoaded) => {
if (userLoaded) {
this.router.navigate(['./']);
} else {
if (!environment.production) {
console.log('An error happened: user wasn\'t loaded.');
}
}
});
this.openIdConnectService.handleCallback();
}
-
redirect-silent-renew
component
export class RedirectSilentRenewComponent implements OnInit {
constructor(private openIdConnectService: OpenIdConnectService) { }
ngOnInit() {
this.openIdConnectService.handleSilentCallback();
}
}
-
RequireAuthenticatedUserRoute
Guard
export class RequireAuthenticatedUserRouteGuard implements CanActivate {
constructor(
private openIdConnectService: OpenIdConnectService,
private router: Router
) { }
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
if (this.openIdConnectService.userAvailable) {
return true;
} else {
// trigger signin
this.openIdConnectService.triggerSignIn();
return false;
}
}
}
- 注册服务
declarations: [
AppComponent,
SigninOidcComponent,
RedirectSilentRenewComponent
],
providers: [
OpenIdConnectService,
RequireAuthenticatedUserRouteGuard,
],
- 路由配置
- app-routing
const routes: Routes = [
{ path: 'blog', loadChildren: './blog/blog.module#BlogModule' },
{ path: 'signin-oidc', component: SigninOidcComponent },
{ path: 'redirect-silentrenew', component: RedirectSilentRenewComponent },
{ path: '**', redirectTo: 'blog' }
];
- post-routing
const routes: Routes = [
{
path: '', component: BlogAppComponent,
children: [
{ path: 'post-list', component: PostListComponent, canActivate: [RequireAuthenticatedUserRouteGuard] },
{ path: '**', redirectTo: 'post-list' }
]
}
];