- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章详解在ASP.NET Core中使用Angular2以及与Angular2的Token base身份认证由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
Angular2是对Angular1的一次彻底的,破坏性的更新.
相对于Angular1.x,借用某果的广告语,唯一的不同,就是处处都不同.
•首先,推荐的语言已经不再是Javascript,取而代之的TypeScript,(TypeScript = ES6 + 类型系统 + 类型注解), TypeScriipt的类型系统对于开发复杂的单页Web app大有帮助,同时编译成javascript后的执行效率也比大多数手写javascript要快。有兴趣的同学可以查阅官方文档:英文传送门 |中文传送门.
•得益于彻底重构,性能相对于Angular1.x有了大幅提升,也更适合再全平台部署.
•Angular2是基于Component的,Component可以理解为是1.x时代的Controller + $Scope + view 。
•View的很多语法也做了更新,比如<li ng-repeat="movie in vm.movies"></li> 变成了 <li *ngFor="let movie of movies"></li> 。
关于Angular2,强烈建议查阅官方文档:英文传送门| 中文传送门 。
注意:本文章属于Step by step + Code Sample教程,且篇幅较长,建议下载本Sample并跟着本文进度自己重做一遍本例,下载完整代码并分析代码结构才有意义,下载地址:How to authorization Angular 2 app with asp.net core web api 。
1.前期准备 。
•推荐使用VS2015 Update3或更新的版本完成本示例 。
•你需要安装.NET Core开发环境,这里提供VS版: //www.zzvips.com/softs/472362.html 。
•安装Node.js 版本5.0.0或以上,(在本例中,这个主要是编译TypeScript用的)下载地址:Node.js and NPM 。
•NPM 3.0.0或以上,默认NPM会随着Node.js一并安装完毕。(在本例中,这个主要是下载各种Angular的各个包用的,参考VS中的Nuget) 。
2.创建项目 。
在VS中新建项目,项目类型选择 ASP.NET Core Web Application(.Net Core),输入项目名称为:CSAuthorAngular2InASPNetCore,Template选择为Empty. 。
3.在项目中整合Angular2 。
3.1.配置Startup.cs 。
注:添加下面的代码时IDE会报代码错误,这是因为还没有引用对用的包,进入报错的这一行,点击灯泡,加载对应的包就可以了.
(图文无关) 。
在ConfigureServices中添加如下代码 。
1
|
services.AddMvc();
|
这里是添加MVC服务 。
在Configure中添加如下代码 。
1
2
3
4
5
6
7
8
|
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name:
"default"
,
template:
"{controller=Home}/{action=Index}"
);
});
|
第一句是启用静态文件,第二句是应用MVC模式并添加路由配置.
完整的代码应该是这个样子 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public
class
Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
public
void
ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public
void
Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name:
"default"
,
template:
"{controller=Home}/{action=Index}"
);
});
}
}
|
3.2.添加控制器以及视图 。
3.2.1.在项目根目录下添加Controllers目录,并在其中添加一个控制器HomeController.cs,默认代码即可.
3.2.2.在项目跟目录下创建Views目录,在Views目录中新建目录Home, 最后在Home目录中新建视图Index.cshtml,内容应该是这样:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
<
html
>
<
head
>
<
title
>Angular QuickStart</
title
>
<
base
href
=
"/"
>
<
meta
charset
=
"UTF-8"
>
<
meta
name
=
"viewport"
content
=
"width=device-width, initial-scale=1"
>
<!-- 1. Load libraries -->
<!-- Polyfill(s) for older browsers -->
<
script
src
=
"node_modules/core-js/client/shim.min.js"
></
script
>
<
script
src
=
"node_modules/zone.js/dist/zone.js"
></
script
>
<
script
src
=
"node_modules/reflect-metadata/Reflect.js"
></
script
>
<
script
src
=
"node_modules/systemjs/dist/system.src.js"
></
script
>
<!-- 2. Configure SystemJS -->
<
script
src
=
"systemjs.config.js"
></
script
>
<
script
>
System.import('app').catch(function(err){ console.error(err); });
</
script
>
</
head
>
<!-- 3. Display the application -->
<
body
>
<
my-app
>Loading...</
my-app
>
</
body
>
</
html
>
|
现在运行项目的话你仅仅能看到一个Loading,再控制台中你还能看到错误,这是因为我们还没有配置Angular。让我们前往wwwroot目录.
3.3.在项目的wwwroot目录中添加如下结构
3.3.1搭建Angular2基础环境 。
•package.json 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
{
"name"
:
"angular-quickstart"
,
"version"
:
"1.0.0"
,
"scripts"
: {
"start"
:
"tsc && concurrently \"tsc -w\" \"lite-server\" "
,
"lite"
:
"lite-server"
,
"postinstall"
:
"typings install"
,
"tsc"
:
"tsc"
,
"tsc:w"
:
"tsc -w"
,
"typings"
:
"typings"
},
"licenses"
: [
{
"type"
:
"MIT"
,
"url"
:
"https://github.com/angular/angular.io/blob/master/LICENSE"
}
],
"dependencies"
: {
"@angular/common"
:
"2.0.2"
,
"@angular/compiler"
:
"2.0.2"
,
"@angular/core"
:
"2.0.2"
,
"@angular/forms"
:
"2.0.2"
,
"@angular/http"
:
"2.0.2"
,
"@angular/platform-browser"
:
"2.0.2"
,
"@angular/platform-browser-dynamic"
:
"2.0.2"
,
"@angular/router"
:
"3.0.2"
,
"@angular/upgrade"
:
"2.0.2"
,
"angular-in-memory-web-api"
:
"0.1.5"
,
"bootstrap"
:
"3.3.7"
,
"core-js"
:
"2.4.1"
,
"reflect-metadata"
:
"0.1.8"
,
"rxjs"
:
"5.0.0-beta.12"
,
"systemjs"
:
"0.19.39"
,
"zone.js"
:
"0.6.25"
},
"devDependencies"
: {
"concurrently"
:
"3.0.0"
,
"gulp"
:
"^3.9.1"
,
"lite-server"
:
"2.2.2"
,
"typescript"
:
"2.0.3"
,
"typings"
:
"1.4.0"
}
}
|
•systemjs.config.js 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
(
function
(global) {
System.config({
paths: {
// paths serve as alias
'npm:'
:
'node_modules/'
},
// map tells the System loader where to look for things
map: {
// our app is within the app folder
app:
'app'
,
// angular bundles
'@angular/core'
:
'npm:@angular/core/bundles/core.umd.js'
,
'@angular/common'
:
'npm:@angular/common/bundles/common.umd.js'
,
'@angular/compiler'
:
'npm:@angular/compiler/bundles/compiler.umd.js'
,
'@angular/platform-browser'
:
'npm:@angular/platform-browser/bundles/platform-browser.umd.js'
,
'@angular/platform-browser-dynamic'
:
'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js'
,
'@angular/http'
:
'npm:@angular/http/bundles/http.umd.js'
,
'@angular/router'
:
'npm:@angular/router/bundles/router.umd.js'
,
'@angular/forms'
:
'npm:@angular/forms/bundles/forms.umd.js'
,
'@angular/upgrade'
:
'npm:@angular/upgrade/bundles/upgrade.umd.js'
,
// other libraries
'rxjs'
:
'npm:rxjs'
,
'angular-in-memory-web-api'
:
'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js'
},
// packages tells the System loader how to load when no filename and/or no extension
packages: {
app: {
main:
'./main.js'
,
defaultExtension:
'js'
},
rxjs: {
defaultExtension:
'js'
}
}
});
})(
this
);
|
•tsconfig.js 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
{
"compileOnSave"
:
true
,
"compilerOptions"
: {
"target"
:
"es5"
,
"module"
:
"commonjs"
,
"moduleResolution"
:
"node"
,
"sourceMap"
:
true
,
"emitDecoratorMetadata"
:
true
,
"experimentalDecorators"
:
true
,
"removeComments"
:
false
,
"noImplicitAny"
:
false
},
"exclude"
: [
"node_modules"
]
}
|
•typings.json(注,在最新文档中typings已被npm的@types替代,参见官方文档:文档变更日志) 。
1
2
3
4
5
6
7
|
{
"globalDependencies"
: {
"core-js"
:
"registry:dt/core-js#0.0.0+20160725163759"
,
"jasmine"
:
"registry:dt/jasmine#2.2.0+20160621224255"
,
"node"
:
"registry:dt/node#6.0.0+20160909174046"
}
}
|
右击wwwroot中的Package.json,选择Restore Packages(或者在CMD下进入wwwroot目录,并执行命令 npm install),npm会去下载需要的包,并存储于node_modules目录中.
3.3.2.配置启动文件以启用Angular2 。
在wwwroot下新建目录app,app拥有如下文件:
•app.component.ts 。
1
2
3
4
5
6
7
8
9
|
import { Component } from
'@angular/core'
;
@Component({
moduleId: module.id,
selector:
'my-app'
,
template:
"this is in angular2"
,
})
export class AppComponent {
}
|
可以发现被@Component装饰属性装饰了AppComponent,selector指代你Component的占位符,比如本例中你可以再Home/index.cshtml中发现一段这样的标记 。
1
|
<
my-app
>Loading...</
my-app
>
|
template既为该Component的View,不要忘记moduleId,不添加它会出现很多奇怪的问题.
•app.module.ts 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
import { NgModule } from
"@angular/core"
;
import { BrowserModule } from
"@angular/platform-browser"
;
import { AppComponent } from
"./app.component"
;
@NgModule({
bootstrap: [AppComponent],
imports: [
BrowserModule
],
declarations: [
AppComponent
]
})
export class AppModule { }
|
•main.ts 。
1
2
3
4
|
import { platformBrowserDynamic } from
'@angular/platform-browser-dynamic'
;
import { AppModule } from
'./app.module'
;
const platform = platformBrowserDynamic();
platform.bootstrapModule(AppModule);
|
基础整合完毕.
按F5 Debug一下,现在你能再浏览器中看到一句话:this is in angular 2 。
4.实现身份认证 。
废了半天劲,看着很傻,没有任何成就感。怎么办,让我们再深入一点,接下来我们来为Angular2完成一个Token base的身份验证,我会把Angular2的routing,data bind,service,http,等等你工作中最常用到的挨个演示一遍.
4.1.Server端 。
4.1.1.创建一些辅助类 。
4.1.1.1.在项目根目录下创建一个文件夹Auth,并添加RSAKeyHelper.cs以及TokenAuthOption.cs两个文件 。
•在RSAKeyHelper.cs中 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
using
System.Security.Cryptography;
namespace
CSTokenBaseAuth.Auth
{
public
class
RSAKeyHelper
{
public
static
RSAParameters GenerateKey()
{
using
(var key =
new
RSACryptoServiceProvider(2048))
{
return
key.ExportParameters(
true
);
}
}
}
}
|
•在TokenAuthOption.cs中 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
using
System;
using
Microsoft.IdentityModel.Tokens;
namespace
CSTokenBaseAuth.Auth
{
public
class
TokenAuthOption
{
public
static
string
Audience {
get
; } =
"ExampleAudience"
;
public
static
string
Issuer {
get
; } =
"ExampleIssuer"
;
public
static
RsaSecurityKey Key {
get
; } =
new
RsaSecurityKey(RSAKeyHelper.GenerateKey());
public
static
SigningCredentials SigningCredentials {
get
; } =
new
SigningCredentials(Key, SecurityAlgorithms.RsaSha256Signature);
public
static
TimeSpan ExpiresSpan {
get
; } = TimeSpan.FromMinutes(20);
}
}
|
4.1.1.2.在项目根目录下创建目录Model,并在其中添加RequestResult.cs,代码应该是这样.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public
class
RequestResult
{
public
RequestState State {
get
;
set
; }
public
string
Msg {
get
;
set
; }
public
Object Data {
get
;
set
; }
}
public
enum
RequestState
{
Failed = -1,
NotAuth = 0,
Success = 1
}
|
4.1.2更新Startup.cs 。
在ConfigureServices中添加如下代码:
1
2
3
4
5
6
|
services.AddAuthorization(auth =>
{
auth.AddPolicy(
"Bearer"
,
new
AuthorizationPolicyBuilder()
.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
.RequireAuthenticatedUser().Build());
});
|
这里是添加身份认证服务 。
在Configure方法中添加如下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
app.UseExceptionHandler(appBuilder =>
{
appBuilder.Use(async (context, next) =>
{
var error = context.Features[
typeof
(IExceptionHandlerFeature)]
as
IExceptionHandlerFeature;
//when authorization has failed, should retrun a json message to client
if
(error !=
null
&& error.Error
is
SecurityTokenExpiredException)
{
context.Response.StatusCode = 401;
context.Response.ContentType =
"application/json"
;
await context.Response.WriteAsync(JsonConvert.SerializeObject(
new
RequestResult
{
State = RequestState.NotAuth,
Msg =
"token expired"
}));
}
//when orther error, retrun a error message json to client
else
if
(error !=
null
&& error.Error !=
null
)
{
context.Response.StatusCode = 500;
context.Response.ContentType =
"application/json"
;
await context.Response.WriteAsync(JsonConvert.SerializeObject(
new
RequestResult
{
State = RequestState.Failed,
Msg = error.Error.Message
}));
}
//when no error, do next.
else
await next();
});
});
|
本段是Handle当身份认证失败时抛出的异常,并返回合适的json 。
在相同的方法中添加另外一段代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
app.UseJwtBearerAuthentication(
new
JwtBearerOptions()
{
TokenValidationParameters =
new
TokenValidationParameters()
{
IssuerSigningKey = TokenAuthOption.Key,
ValidAudience = TokenAuthOption.Audience,
ValidIssuer = TokenAuthOption.Issuer,
// When receiving a token, check that we've signed it.
ValidateIssuerSigningKey =
true
,
// When receiving a token, check that it is still valid.
ValidateLifetime =
true
,
// This defines the maximum allowable clock skew - i.e. provides a tolerance on the token expiry time
// when validating the lifetime. As we're creating the tokens locally and validating them on the same
// machines which should have synchronised time, this can be set to zero. Where external tokens are
// used, some leeway here could be useful.
ClockSkew = TimeSpan.FromMinutes(0)
}
});
|
本段代码是应用JWTBearerAuthentication身份认证.
4.1.3.TokenAuthController.cs 。
在Controllers中新建一个Web API Controller Class,命名为TokenAuthController.cs。我们将在这里完成登录授权, 。
在同文件下添加两个类,分别用来模拟用户模型,以及用户存储,代码应该是这样
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public
class
User
{
public
Guid ID {
get
;
set
; }
public
string
Username {
get
;
set
; }
public
string
Password {
get
;
set
; }
}
public
static
class
UserStorage
{
public
static
List<User> Users {
get
;
set
; } =
new
List<User> {
new
User {ID=Guid.NewGuid(),Username=
"user1"
,Password =
"user1psd"
},
new
User {ID=Guid.NewGuid(),Username=
"user2"
,Password =
"user2psd"
},
new
User {ID=Guid.NewGuid(),Username=
"user3"
,Password =
"user3psd"
}
};
}
|
接下来在TokenAuthController.cs中添加如下方法 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
private
string
GenerateToken(User user, DateTime expires)
{
var handler =
new
JwtSecurityTokenHandler();
ClaimsIdentity identity =
new
ClaimsIdentity(
new
GenericIdentity(user.Username,
"TokenAuth"
),
new
[] {
new
Claim(
"ID"
, user.ID.ToString())
}
);
var securityToken = handler.CreateToken(
new
SecurityTokenDescriptor
{
Issuer = TokenAuthOption.Issuer,
Audience = TokenAuthOption.Audience,
SigningCredentials = TokenAuthOption.SigningCredentials,
Subject = identity,
Expires = expires
});
return
handler.WriteToken(securityToken);
}
|
该方法仅仅只是生成一个Auth Token,接下来我们来添加另外一个方法来调用它 。
在相同文件中添加如下代码 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
[HttpPost]
public
string
GetAuthToken(User user)
{
var existUser = UserStorage.Users.FirstOrDefault(u => u.Username == user.Username && u.Password == user.Password);
if
(existUser !=
null
)
{
var requestAt = DateTime.Now;
var expiresIn = requestAt + TokenAuthOption.ExpiresSpan;
var token = GenerateToken(existUser, expiresIn);
return
JsonConvert.SerializeObject(
new
{
stateCode = 1,
requertAt = requestAt,
expiresIn = TokenAuthOption.ExpiresSpan.TotalSeconds,
accessToken = token
});
}
else
{
return
JsonConvert.SerializeObject(
new
{ stateCode = -1, errors =
"Username or password is invalid"
});
}
}
|
接下来我们来完成授权部分,在相同的文件中添加如下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public
string
GetUserInfo()
{
var claimsIdentity = User.Identity
as
ClaimsIdentity;
return
JsonConvert.SerializeObject(
new
RequestResult
{
State = RequestState.Success,
Data =
new
{
UserName = claimsIdentity.Name
}
});
}
|
为方法添加装饰属性 。
[HttpGet] 。
[Authorize("Bearer")] 。
第二行代码说明这个action需要身份验证.
该文件完整的代码应该是这个样子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
Microsoft.AspNetCore.Mvc;
using
CSAuthorAngular2InASPNetCore.Auth;
using
System.IdentityModel.Tokens.Jwt;
using
Newtonsoft.Json;
using
System.Security.Claims;
using
System.Security.Principal;
using
Microsoft.IdentityModel.Tokens;
using
CSAuthorAngular2InASPNetCore.Model;
using
Microsoft.AspNetCore.Authorization;
namespace
CSAuthorAngular2InASPNetCore.Controllers
{
[Route(
"api/[controller]"
)]
public
class
TokenAuthController : Controller
{
[HttpPost]
public
string
GetAuthToken([FromBody]User user)
{
var existUser = UserStorage.Users.FirstOrDefault(u => u.Username == user.Username && u.Password == user.Password);
if
(existUser !=
null
)
{
var requestAt = DateTime.Now;
var expiresIn = requestAt + TokenAuthOption.ExpiresSpan;
var token = GenerateToken(existUser, expiresIn);
return
JsonConvert.SerializeObject(
new
RequestResult
{
State = RequestState.Success,
Data =
new
{
requertAt = requestAt,
expiresIn = TokenAuthOption.ExpiresSpan.TotalSeconds,
tokeyType = TokenAuthOption.TokenType,
accessToken = token
}
});
}
else
{
return
JsonConvert.SerializeObject(
new
RequestResult
{
State = RequestState.Failed,
Msg =
"Username or password is invalid"
});
}
}
private
string
GenerateToken(User user, DateTime expires)
{
var handler =
new
JwtSecurityTokenHandler();
ClaimsIdentity identity =
new
ClaimsIdentity(
new
GenericIdentity(user.Username,
"TokenAuth"
),
new
[] {
new
Claim(
"ID"
, user.ID.ToString())
}
);
var securityToken = handler.CreateToken(
new
SecurityTokenDescriptor
{
Issuer = TokenAuthOption.Issuer,
Audience = TokenAuthOption.Audience,
SigningCredentials = TokenAuthOption.SigningCredentials,
Subject = identity,
Expires = expires
});
return
handler.WriteToken(securityToken);
}
[HttpGet]
[Authorize(
"Bearer"
)]
public
string
GetUserInfo()
{
var claimsIdentity = User.Identity
as
ClaimsIdentity;
return
JsonConvert.SerializeObject(
new
RequestResult
{
State = RequestState.Success,
Data =
new
{
UserName = claimsIdentity.Name
}
});
}
}
public
class
User
{
public
Guid ID {
get
;
set
; }
public
string
Username {
get
;
set
; }
public
string
Password {
get
;
set
; }
}
public
static
class
UserStorage
{
public
static
List<User> Users {
get
;
set
; } =
new
List<User> {
new
User {ID=Guid.NewGuid(),Username=
"user1"
,Password =
"user1psd"
},
new
User {ID=Guid.NewGuid(),Username=
"user2"
,Password =
"user2psd"
},
new
User {ID=Guid.NewGuid(),Username=
"user3"
,Password =
"user3psd"
}
};
}
}
|
4.2Angular2端 。
4.2.1创建View Model 。
在wwwroot/app下创建一个目录:_model, 并添加一个Typescript文件RequestResult.ts,内容应该是这样.
1
2
3
4
5
|
export class RequestResult {
State: number;
Msg: string;
Data: Object;
}
|
4.2.2创建Service 。
在wwwroot/app下创建一个目录:_services,并添加一个Typescript文件auth.service.ts,内容应该是这样.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
import { Injectable } from
"@angular/core"
;
import { Headers, Http } from
"@angular/http"
;
import
"rxjs/add/operator/toPromise"
;
import { RequestResult } from
"../_model/RequestResult"
;
@Injectable()
export class AuthService {
private tokeyKey =
"token"
;
private token: string;
constructor(
private http: Http
) { }
login(userName: string, password: string): Promise<RequestResult> {
return
this
.http.post(
"/api/TokenAuth"
, { Username: userName, Password: password }).toPromise()
.then(response => {
let result = response.json() as RequestResult;
if
(result.State == 1) {
let json = result.Data as any;
sessionStorage.setItem(
"token"
, json.accessToken);
}
return
result;
})
.
catch
(
this
.handleError);
}
checkLogin(): boolean {
var
token = sessionStorage.getItem(
this
.tokeyKey);
return
token !=
null
;
}
getUserInfo(): Promise<RequestResult> {
return
this
.authGet(
"/api/TokenAuth"
);
}
authPost(url: string, body: any): Promise<RequestResult> {
let headers =
this
.initAuthHeaders();
return
this
.http.post(url, body, { headers: headers }).toPromise()
.then(response => response.json() as RequestResult)
.
catch
(
this
.handleError);
}
authGet(url): Promise<RequestResult> {
let headers =
this
.initAuthHeaders();
return
this
.http.get(url, { headers: headers }).toPromise()
.then(response => response.json() as RequestResult)
.
catch
(
this
.handleError);
}
private getLocalToken(): string {
if
(!
this
.token) {
this
.token = sessionStorage.getItem(
this
.tokeyKey);
}
return
this
.token;
}
private initAuthHeaders(): Headers {
let token =
this
.getLocalToken();
if
(token ==
null
)
throw
"No token"
;
var
headers =
new
Headers();
headers.append(
"Authorization"
,
"Bearer "
+ token);
return
headers;
}
private handleError(error: any): Promise<any> {
console.error(
'An error occurred'
, error);
return
Promise.reject(error.message || error);
}
}
|
本文件主要用来完成登录以及登录验证工作,之后该service将可以被注入到Component中以便被Component调用.
注:主要的逻辑都应该写到service中 。
4.2.3.创建Component 。
4.2.3.1.在wwwroot/app下创建一个目录home,该目录用来存放HomeComponent,home应拥有如下文件:
•home.component.ts 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
import { Component, OnInit } from
"@angular/core"
;
import { AuthService } from
"../_services/auth.service"
;
@Component({
moduleId: module.id,
selector:
"my-home"
,
templateUrl:
"view.html"
,
styleUrls: [
"style.css"
]
})
export class HomeComponent implements OnInit {
isLogin =
false
;
userName: string;
constructor(
private authService: AuthService
) { }
ngOnInit(): void {
this
.isLogin =
this
.authService.checkLogin();
if
(
this
.isLogin) {
this
.authService.getUserInfo().then(res => {
this
.userName = (res.Data as any).UserName;
});
}
}
}
|
查阅代码,在@Component中指定了View以及style.
AuthService被在构造方法中被注入了本Component,ngOnInit是接口OnInit的一个方法,他在Component初始化时会被调用.
•style.css 。
1
|
/*styles of this view*/
|
本例中没有添加任何样式,如有需要可以写在这里.
•view.html 。
1
2
3
4
5
6
7
8
|
<
div
*
ngIf
=
"isLogin"
>
<
h1
>Hi <
span
>{{userName}}</
span
></
h1
>
</
div
>
<
div
*
ngIf
=
"!isLogin"
>
<
h1
>please login</
h1
>
<
a
routerLink
=
"/login"
>Login</
a
>
</
div
>
|
*ngIf=""是Angular2 的其中一种标记语法,作用是当返回真时渲染该节点,完整教程请参阅官方文档.
4.2.3.2.在wwwroot/app下创建目录Login,该目录用来存放LoginComponent,文件结构类似于上一节.
•login.component.ts 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
import { Component } from
"@angular/core"
;
import { Router } from
'@angular/router'
;
import { AuthService } from
"../_services/auth.service"
;
@Component({
moduleId: module.id,
selector:
"my-login"
,
templateUrl:
"view.html"
,
styleUrls: [
"style.css"
]
})
export class LoginComponent {
private userName: string;
private password: string;
constructor(
private authService: AuthService,
private router: Router
) { }
login() {
this
.authService.login(
this
.userName,
this
.password)
.then(result => {
if
(result.State == 1) {
this
.router.navigate([
"./home"
]);
}
else
{
alert(result.Msg);
}
});
}
}
|
•style.css 。
1
|
/*styles of this view*/
|
•view.html 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<
table
>
<
tr
>
<
td
>userName:</
td
>
<
td
><
input
[(ngModel)]="userName"
placeholder
=
"useName:try type user1"
/></
td
>
</
tr
>
<
tr
>
<
td
>userName:</
td
>
<
td
><
input
[(ngModel)]="password"
placeholder
=
"password:try type user1psd"
/></
td
>
</
tr
>
<
tr
>
<
td
></
td
>
<
td
><
input
type
=
"button"
(click)="login()"
value
=
"Login"
/></
td
>
</
tr
>
</
table
>
|
4.2.4.应用路由 。
路由是切换多页面用的.
在wwwroot/app下新建一个Typescript文件,命名为app-routing.module.ts,内容应该是这个样子.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
import { NgModule } from
"@angular/core"
;
import { RouterModule, Routes } from
"@angular/router"
;
import { HomeComponent } from
"./home/home.component"
;
import { LoginComponent } from
"./login/login.component"
const routes: Routes = [
{ path:
""
, redirectTo:
"/home"
, pathMatch:
"full"
},
{ path:
"home"
, component: HomeComponent },
{ path:
"login"
, component: LoginComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
|
接下来我们来应用这个路由, 。
打开app.module.ts,更新代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
import { NgModule } from
"@angular/core"
;
import { BrowserModule } from
"@angular/platform-browser"
;
import { HttpModule } from
"@angular/http"
;
import { FormsModule } from
"@angular/forms"
;
import { AppRoutingModule } from
"./app-routing.module"
;
import { AuthService } from
"./_services/auth.service"
;
import { AppComponent } from
"./app.component"
;
import { HomeComponent } from
"./home/home.component"
;
import { LoginComponent } from
"./login/login.component"
;
@NgModule({
bootstrap: [AppComponent],
imports: [
BrowserModule,
HttpModule,
AppRoutingModule,
FormsModule
],
declarations: [
AppComponent,
HomeComponent,
LoginComponent
],
providers: [AuthService]
})
export class AppModule { }
|
NgModule和BrowserModule你可以理解为基础模块,必加的.
HttpModule是做http请求用的.
FormsModule是做双向数据绑定用的,比如下面这样的,如果想把数据从view更新到component,就必须加这个.
1
|
<
input
[(ngModel)]="userName"
placeholder
=
"useName:try type user1"
/>
|
AppRoutingModule即为我们刚才添加的路由文件.
AuthService是我们最早添加的service文件.
AppComponent是我们最初添加的那个app.component.ts里的那个component. 。
HomeComponent,LoginComponent同上.
最后我们再app.component.ts中添加路由锚点, 。
把template的值为 "<router-outlet></router-outlet>" 。
完整的代码应该是这样:
1
2
3
4
5
6
7
8
9
|
import { Component } from
'@angular/core'
;
@Component({
moduleId: module.id,
selector:
'my-app'
,
template:
"<router-outlet></router-outlet>"
,
})
export class AppComponent {
}
|
router-outlet是路由锚点的关键词.
至此,所有代码完成,F5调试吧.
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我.
原文链接:http://www.cnblogs.com/onecodeonescript/p/6062203.html 。
最后此篇关于详解在ASP.NET Core中使用Angular2以及与Angular2的Token base身份认证的文章就讲到这里了,如果你想了解更多关于详解在ASP.NET Core中使用Angular2以及与Angular2的Token base身份认证的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我试图对 ASP.Net MVC 有一个高层次的理解,我开始意识到它看起来很像原始的 ASP 脚本。过去,我们将“模型”/业务逻辑代码组织到 VBScript 类或 VB COM 组件中。 当然,现在
我已经搜索了一段时间,但似乎找不到答案。 我想在我的旋转木马中显示一个计数器,左边是当前项目(工作),左边是项目总数。 我的代码:
. 最佳答案 Scott Gu 称这些为代码块。这就是我的看法。 http://weblogs.asp.net/scottgu/archive/2010/04/06/new-lt-gt-syntax
我有一个使用 Visual Studio 2010/.net 4/VB 制作的网站。 我真的很喜欢我发现的 FAQ 系统的布局,因为它很简单,但它是经典的 asp。所以,显然,我不能包括我的母版页布局
好吧,对于你们许多人来说,这个问题可能有一个非常明显的答案,但它让我难住了。 我有一个 asp.net Web 表单,上面有两个控件(嗯,不止这两个,但我们将重点关注这些) - 第一个是 asp:dr
当我将 ASP.NET 复选框控件设置为 asp.net 更新面板的异步回发触发器时,EventName 属性是什么? 最佳答案 我相信它是 CheckedChanged。 关于asp.net - a
我有一个用经典 asp 编写的(巨大的)网站。现在我必须切换到 vb.net (razor)。有没有办法将这两个结合起来直到切换完成? 有没有办法让应用程序与经典的 asp 和 vb.net 一起工作
I am creating a products page, where the user selects an option in a radiobuttonlist for example, an
我最近将一个经典的 ASP 应用程序转换为 ASP.NET 3.5,但我觉得我的经典 ASP 版本要快一些(我不知道可能买家会后悔)。 所以你们能帮我解决这个问题吗,让我知道哪个更快,asp、asp.
从本周开始,我被要求开始学习如何使用 ASP 开发网站。我通过 XNA 对 C# 有一定的经验,所以这部分对我来说并不是什么麻烦。 我一直在关注Music Store Tutorial这需要我设置一个
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 8 年前。 Improve this ques
我想将一些表单变量发布到经典 ASP 页面中。我不想改变经典的 ASP 页面,因为需要完成大量的工作,以及消耗它们的页面数量。 经典的 ASP 页面需要将表单变量 Username 和 Userpas
已结束。此问题正在寻求书籍、工具、软件库等的推荐。它不满足Stack Overflow guidelines 。目前不接受答案。 我们不允许提出寻求书籍、工具、软件库等推荐的问题。您可以编辑问题,以便
在某种程度上,这可能是一个异端问题。我们有一个大型站点,其中许多页面仍在ASP中。通常,并没有真正动态的,而是包括(通过SSI或Server.Execute)定期重新生成的HTML块。看起来好像是一个
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 9 年前。 Improve this ques
我有一个遗留的 ASP 应用程序——在不久的某个时候——需要迁移到 ASP.Net 2.0(以与也在 2.0 中的其他应用程序兼容)。 对于这类事情是否有最佳实践,即作为第一步将当前 html、vbs
我目前在一家公司工作,该公司使用 ASP.NET Webforms 和旧 ASP 页面的组合进行 Web 开发。这对于他们当前的项目来说效果很好,但我想说服/建议他们切换到 ASP.NET MVC,因
我有一个经典的 asp 应用程序。我想将该页面的竞赛表格发布到 Asp.Net 表格。原因是我想在进入数据库之前使用我在 Asp.Net 页面中内置的大量逻辑进行验证,而我对 asp 不太了解。更不用
我知道在 ASP.NET MVC 中,您可以拥有移动 View 并执行类似 Index.mobile.cshtml 的操作。和 _Layout.mobile.cshtml并且服务器知道将这些 View
我需要从一些服务器端 c#.net 代码中调用经典 asp 页面上的 VBscript 函数 - 有谁知道一种干净的方法来做到这一点?在 .net 中重写函数不是一种选择。 我会再解释一下这个问题..
我是一名优秀的程序员,十分优秀!