4
votes

I am new to react but not to asp.net core application development. I am trying to create a react application with asp.net core + react template in visual studio. I am trying to do a Asp.Net MVC route first to call controller action which has [Authorize] attribute to make sure user is authenticated. I do not have any thing to show in Asp.Net MVC view. I want to immediately redirect user to react default route once user is authenticated via asp.net mvc controller action. Is there any specific routing mechanism to achieve that.

Right now my application goes through controller and action based on route and stops at view defined by controller action. I am trying to understand how to redirect user to use react route now. I tried using return redirecttoaction and returnredirecttoroute but no luck.

My Asp.Net Core MVC Action

[Authorize]
public ActionResult Index()
{
    var IsAuthenticated = HttpContext.User.Identity.IsAuthenticated;
    var UserName = "Guest";
    if (IsAuthenticated)
    {
        UserName = HttpContext.User.Identity.Name;
    }
    TempData["userName"] = UserName;

    //return View();
    return Redirect("my react first page");
}

I tried return Redirect("my react first page");

My Startup file method used for routing

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
                else
                {
                    app.UseExceptionHandler("/Error");
                    app.UseHsts();
                }

                app.UseHttpsRedirection();
                app.UseStaticFiles();
                app.UseSpaStaticFiles();
                app.UseAuthentication();


//MVC Part. I am trying this to authorize as FIRST step
                app.UseMvc(routes =>
                {
                    routes.MapRoute(
                        name: "default",
                        template: "{controller=DataAccess}/{action=Index}/{id?}");
                });

// React part I am trying this to be called once Authentication is done in controller action. Trying to call this as a SECOND step

                app.UseSpa(spa =>
                {
                    spa.Options.SourcePath = "ClientApp";

                    if (env.IsDevelopment())
                    {
                        spa.UseReactDevelopmentServer(npmScript: "start");
                    }
                });
            }

If I do a redirect and force the react route will there be any issue missing react route features? I see this spa.UseReactDevelopmentServer(npmScript: "start"); is taking more time showing a timeout if I do a redirect. Any solution where User can be redirected to controller action do all authorization and use react default routing mechanism?

Is there any option to run react server first and do routing as starting server is taking more time leading to timeouts.

Note: I used Create-React-App to create my app.

5
MVC Authentication is server side, and React route is client side. For SPA and MVC backend, your client route is controlled by react and then react send request to backend to request resouce with checking the authentication. If you want to control the access to react page, you could refer Permission checks from components in a React/Redux applicationEdward
Do you want to keep two (reactjs and .net core) different servers running at the same time?Rahul Raut

5 Answers

4
votes

Dont setup the same routes for both, let the server find the non React view, and let React have it own routes and view/templates

1
votes

You should setup client side routing in react and server side routing in asp.net core.

Please note that client side routes are only limited to browser. They are not known to the server.

When you try to change page in react, browser (without sending request to server) redirects user to other page - provided you do not need any other information from server for this redirection.

In my opinion, you should design application in such a way that your server should not directly affect the routes defined in client side routing.

The ideal flow (again, in my opinion) for routing based on some decision on asp.net server would be:

  • The client calls server for some decision
  • Server sends response back to react
  • React then interprets response and decides whether to redirect or not.
  • If user is to be redirected, then where it should be redirected.

This logic (or any other similar logic) will also keep your server side logic completely decoupled from the client side technology.

1
votes

I would not recommend doing any sort of routing or redirecting on the server side. This will complicate development, and also double the amount of work. The easier way is to handle routing or redirecting on the client side. This will be more maintainable from a code perspective as well.

From React, when the user logs in, call your controller action to do the authentication/authorization. You can then redirect appropriately with React depending on the response(e.g. a successful login redirects to the user's dashboard, a failed login displays an authentication error etc.)

1
votes

I've worked through this problem with .net core and react as well.

React: Set up an HOC for your routing. Have that hoc hit the backend to see if the user is authorized. If not redirect to login.

.Net Core: Set up a basic path for the HOC to hit and verify the user is authorized.

Here's a complete write up on my github (although it is with jwt tokens): https://github.com/moh704/AuthenticationExample

//Routing with HOC:
class App extends Component {
  render() {
    return (
        <Provider store={store}>
          <ConnectedRouter history={history}>
            <Switch>
              <Route component={SignIn} exact path='/'/>
              <PrivateRoute component={Home} path='/Home'/> //Token will have to be valid in order to access this route.
            </Switch>
          </ConnectedRouter>
        </Provider>
    );
  }
}

//PrivateRoute Component:
interface PrivateRouteProps extends RouteProps {
  component:
    | React.ComponentType<RouteComponentProps<any>>
    | React.ComponentType<any>;
}

interface State {
  validatingUser: boolean,
  userAllowed: boolean
}

class PrivateRouter extends React.Component<PrivateRouteProps, State> {
  state: State = {
    validatingUser: true,
    userAllowed: false
  };

  componentDidMount(): void {
    this.checkUserStatus();
  }

  checkUserStatus = async() => {
    const token = localStorage.getItem('token');
    if (token){
      await axios.get(UserRoutes.GET_TOKEN_STATUS)
        .then(() => this.setState({userAllowed: true, validatingUser: false}))
        .catch(() => this.setState({userAllowed: true, validatingUser: false}));
    } else
      this.setState({userAllowed: false, validatingUser: false});
  };

  render() {
    const { component, ...rest} = this.props;
    return(
      !this.state.validatingUser ?
        <Route
          {...rest}
          render={props =>
            this.state.userAllowed ? (
              <this.props.component {...props} />
            ) : (
              <Redirect // <---- **Redirect magic happens here you're aiming for**
                to={{
                  pathname: "/"
                }}
              />
            )
          }
        /> : <div>loading...</div>
    )
  }
}
export default PrivateRouter;

For .net just create a simple get route that will return okay if authorized. Otherwise, it will return an unauthorized or forbidden:

[HttpGet]
[Authorize]
public IActionResult CheckUserState()
{
   return Ok();
}
0
votes

You can make the main react page a view it returns.

Then your controller can return that view or you can make a controller that will return that view and redirect there.