在阅读本文之前,希望您已经对ASP.NET Core或者Web应用的身份认证机制有所了解。本文主要讲述Blazor WebAssembly模式下的身份认证和授权方法,以及页面元素访问控制,假如您对ASP.NET Core身份认证机制还不了解,可以查看该链接获取完整的sso——统一登录示例。
AuthorizeView是blazor中用于身份认证的内置组件。
Hello, @context.User.Identity.Name!
You can only see this content if you're authenticated.
在AuthorizeView组件包裹的代码段中,可以使用类型为 AuthenticationState的context变量,因此你可以获取到用户的名称,角色等内容。
AuthenticationState对象包含着用户身份信息,这个对象是由你自己创建出来的,AuthorizeView组件通过级联参数的形式来拿到。
你可以通过实现自己的AuthenticationStateProvider 服务,来创建用户身份信息,即 ClaimsPrincipal 。
如何实现一个具有登录/注销功能的Blazor应用呢?答案就是实现AuthenticationStateProvider服务。无论你是要对接已有的第三方统一登录平台,或是通过查询应用自身的用户数据库。
AuthenticationStateProvider类有一个方法需要你去重写:
Task GetAuthenticationStateAsync()
该方法是完成用户身份认证的唯一方法,你要重写它,并且用你自己的方式创造出一个包含认证信息的AuthenticationState对象。之后,你便可以在任何页面使用依赖注入获取一个Task< AuthenticationState>对象,并且AuthorizeView组件才能发挥作用。
在这里为大家附上一段实现示例:
public override async Task GetAuthenticationStateAsync()
{
var principal = await GetUserPrincipalAsync();
var authState = new AuthenticationState(principal);
NotifyAuthenticationStateChanged(Task.FromResult(authState));
return authState;
}
NotifyAuthenticationStateChanged回调函数是为了通知UI对象状态改变,其重点在于GetUserPrincipalAsync()方法,即如何获取用户身份令牌。
相信大家对用户身份令牌已经有所了解,令牌创建需要身份标识对象-ClaimsIdentity,标识则由一些Claim构成,Claim更像是标识了用户身份的
下面给出一个通过HttpClient调用第三方登录接口的令牌获取示例
private async Task GetUserPrincipalAsync()
{
#if DEBUG
return new ClaimsPrincipal(new ClaimsIdentity(new List()));
#endif
var request = new HttpRequestMessage(HttpMethod.Get, "/login/Auth/UserInfo");
request.SetBrowserRequestCredentials(BrowserRequestCredentials.Include);
var response = await _serviceClient.SendAsync(request);
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
SignIn();
}
var content = await response.Content.ReadAsStringAsync();
if (string.IsNullOrWhiteSpace(content))
{
return new ClaimsPrincipal(new ClaimsIdentity(new List()));
}
var userInfo = JsonConvert.DeserializeObject>(content).Result;
return new ClaimsPrincipal(new ClaimsIdentity(new List
{
new Claim(ClaimTypes.Name, userInfo.Name),
new Claim(ClaimTypes.NameIdentifier, userInfo.IdNumber)
}));
}
该登录接口会检查Http请求中是否带有cookie,token等身份信息,因此我创建了一个HttpRequestMessage对象,并且使用equest.SetBrowserRequestCredentials(BrowserRequestCredentials.Include);
方法来携带浏览器中该域名下的身份信息。 假如请求中存在用户身份信息,则返回用户姓名, Id等数据。然后根据返回数据创建身份令牌。
注意,这里有可能会出现跨域请求的现象,我会在后面的博客中讲述blazor单页应用如何避免这一问题。
假如请求中不存在用户信息,则需要调用SignIn();方法跳转到登录页面,该方法需要自己实现。这里也给出一个示例:
public void SignIn(string customReturnUrl = null)
{
var returnUrl = customReturnUrl != null ? _navigationManager.ToAbsoluteUri(customReturnUrl).ToString() : null;
var encodedReturnUrl = Uri.EscapeDataString(returnUrl ?? _navigationManager.Uri);
var logInUrl = _navigationManager.ToAbsoluteUri($"{GetLoginPath()}?returnUrl={encodedReturnUrl}");
_navigationManager.NavigateTo(logInUrl.ToString(), true);
}
至于退出登录,则更简单了,调用退出接口并返回一个空的令牌即可:
public async Task SignOut(string customReturnUrl = null)
{
await _serviceClient.RequestAsync("/login/account/logout", HttpVerb.Get);
_navigationManager.NavigateTo("/", true);
var anonymousUser = new ClaimsPrincipal(new ClaimsIdentity());
NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(anonymousUser)));
}
看到这里你或许感到疑惑:你这里说的第三方登录平台是怎么实现的?我就想知道这个。本文主要讲述Blazor WebAssembly模式下的身份认证已经授权方法,假如您对ASP.NET Core身份认证机制还有所疑问,可以查看该链接获取完整的sso——统一登录示例。
我会在下篇博客讲述授权机制。