.net core 3.1 with react - 基于身份角色呈现导航菜单项

use*_*664 1 reactjs asp.net-core

我是新手,我正在尝试根据当前用户的角色显示或不显示导航菜单项。在 NavMenu.js (@if(User.IsInRole("Admin"))) 中执行此类操作的正确方法是什么:

render() {
    return (
        <header>
            <Navbar className="navbar-custom navbar-expand-sm navbar-toggleable-sm ng-white border-bottom box-shadow mb-3" light>
                <Container>                        
                    <NavbarToggler onClick={this.toggleNavbar} className="mr-2" />
                    <Collapse className="d-sm-inline-flex flex-sm-row-reverse" isOpen={!this.state.collapsed} navbar>
                        <ul className="navbar-nav flex-grow">
                            @if(User.IsInRole("Admin"))
                            {
                            <NavItem>
                                <NavLink tag={Link} to="/">Home</NavLink>
                            </NavItem>
                            }                                
                            <NavItem>
                                <NavLink tag={Link} to="/counter">Counter</NavLink>
                            </NavItem>
                            <NavItem>
                                <NavLink tag={Link} to="/fetch-data">Fetch data</NavLink>
                            </NavItem>
                            <LoginMenu>
                            </LoginMenu>
                        </ul>
                    </Collapse>
                </Container>
            </Navbar>
        </header>
    );
}
Run Code Online (Sandbox Code Playgroud)

是否可以使用 ClientApp/src/components/api-authorization 目录中的内置 AuthorizeService.js?

Rya*_*yan 7

首先,你需要配置你的IdentityServer,将角色信息添加到token中。然后你可以在React中获取角色user.Profile。最后,使用三目表达基于角色显示内容

1.ProfileService在asp.net core端创建自定义类。

public class ProfileService : IProfileService
{
    protected UserManager<ApplicationUser> mUserManager;

    public ProfileService(UserManager<ApplicationUser> userManager)
    {
        mUserManager = userManager;
    }

    public async Task GetProfileDataAsync(ProfileDataRequestContext context)
    {
        ApplicationUser user = await mUserManager.GetUserAsync(context.Subject);

        IList<string> roles = await mUserManager.GetRolesAsync(user);

        IList<Claim> roleClaims = new List<Claim>();
        foreach (string role in roles)
        {
            roleClaims.Add(new Claim(JwtClaimTypes.Role, role));
        }
        context.IssuedClaims.Add(new Claim(JwtClaimTypes.Name, user.UserName));
        context.IssuedClaims.AddRange(roleClaims);
        //Add more claims as you need
    }

    public Task IsActiveAsync(IsActiveContext context)
    {
        return Task.CompletedTask;
    }
}
Run Code Online (Sandbox Code Playgroud)

2.报名 Startup.cs

public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection")));

        services.AddDefaultIdentity<ApplicationUser>()
            .AddRoles<IdentityRole>()
            .AddRoleManager<RoleManager<IdentityRole>>()     
            .AddEntityFrameworkStores<ApplicationDbContext>();


        services.AddIdentityServer()
             .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();

        services.AddAuthentication()
            .AddIdentityServerJwt();

        services.AddTransient<IProfileService, ProfileService>();
        services.AddControllersWithViews();
        services.AddRazorPages();

        // In production, the React files will be served from this directory
        services.AddSpaStaticFiles(configuration =>
        {
            configuration.RootPath = "ClientApp/build";
        });
    }
Run Code Online (Sandbox Code Playgroud)

3.修改你的 NavMenu.js

import React, { Component } from 'react';
import { Collapse, Container, Navbar, NavbarBrand, NavbarToggler, NavItem, NavLink } from 'reactstrap';
import { Link } from 'react-router-dom';
import { LoginMenu } from './api-authorization/LoginMenu';
import './NavMenu.css';
import authService from './api-authorization/AuthorizeService';

export class NavMenu extends Component {
  static displayName = NavMenu.name;

  constructor (props) {
    super(props);

    this.toggleNavbar = this.toggleNavbar.bind(this);
    this.state = {
        collapsed: true,
        isAuthenticated: false,
        role: null
      };
    }
    componentDidMount() {
        this._subscription = authService.subscribe(() => this.populateState());
        this.populateState();
    }

    componentWillUnmount() {
        authService.unsubscribe(this._subscription);
    }
    async populateState() {
        const [isAuthenticated, user] = await Promise.all([authService.isAuthenticated(), authService.getUser()])
        this.setState({
            isAuthenticated,
            role: user && user.role
        });
    }
      toggleNavbar () {
        this.setState({
          collapsed: !this.state.collapsed
        });
      }

    render() {
        const role = this.state.role;
        return (
          <header>
            <Navbar className="navbar-expand-sm navbar-toggleable-sm ng-white border-bottom box-shadow mb-3" light>
              <Container>
                <NavbarBrand tag={Link} to="/">ReactCore31</NavbarBrand>
                <NavbarToggler onClick={this.toggleNavbar} className="mr-2" />
                <Collapse className="d-sm-inline-flex flex-sm-row-reverse" isOpen={!this.state.collapsed} navbar>
                    <ul className="navbar-nav flex-grow">
                        {
                            role && role.includes("Admin") ?
                                <span>
                                    <NavItem>
                                        <NavLink tag={Link} className="text-dark" to="/">Home</NavLink>
                                    </NavItem>
                                </span>
                                : null}
                        <NavItem>
                            <NavLink tag={Link} className="text-dark" to="/counter">Counter</NavLink>
                        </NavItem>
                        <NavItem>
                            <NavLink tag={Link} className="text-dark" to="/fetch-data">Fetch data</NavLink>
                        </NavItem>
                        <LoginMenu>
                        </LoginMenu>

                      </ul>
                </Collapse>
              </Container>
            </Navbar>
          </header>
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

4. AuthorizeService.js(无变化)

async isAuthenticated() {
    const user = await this.getUser();
    return !!user;
}
async getUser() {
    if (this._user && this._user.profile) {
        return this._user.profile;
    }

    await this.ensureUserManagerInitialized();
    const user = await this.userManager.getUser();
    return user && user.profile;
}
Run Code Online (Sandbox Code Playgroud)