Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG/Feature] MVC Dependency authentication example #1536

Closed
Dexus opened this issue Jun 12, 2020 · 17 comments
Closed

[BUG/Feature] MVC Dependency authentication example #1536

Dexus opened this issue Jun 12, 2020 · 17 comments

Comments

@Dexus
Copy link

Dexus commented Jun 12, 2020

Describe the bug
on the master branch "https://github.com/kataras/iris/blob/master/_examples/mvc/authenticated-controller/main.go" an authentication is used to show how it is done when you search for an authenticated user.
But how can I find an unauthenticated user who can call the same route but from a different controller?

To Reproduce
Steps to reproduce the behavior:

  1. [...]

Expected behavior
Let's take two controllers that are both registered for the same route, but one of them has no authentication feature. Now when I call the route, I want the call without authentication to return a different value than if I were authenticated.

Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS: [e.g. ubuntu, windows]

Additional context
I don't think it's a bug, but a feature request, although I think others do as well, that the same route should call a different controller under different circumstances.

@kataras
Copy link
Owner

kataras commented Jun 12, 2020

Each Controller's method creates a new route, so two controllers can't share the same route with the current implementation. If I am going to change the MVC again, the v12.2.0 release will be delayed even more, I will think of it and come back to you with a solution.

@Dexus
Copy link
Author

Dexus commented Jun 12, 2020

Thanks for the feedback. I look forward to your proposed solution.
It is sometimes bewitching that it is possible with basic functions, again in the MVC something difficult or not at all. But doing it this way will always make things a bit better.

@kataras
Copy link
Owner

kataras commented Jun 14, 2020

Hello @Dexus, I did it without any changes (however you could do it by checking the Authenticated integer value (if == 0 then unauthenticated) on the UserController.GetMe). This feature is available across Iris application, not just MVC. You just Party.SetRegisterRule(iris.RouteOverlap). Updated user authenticated controller example. Please tell me if that suits your needs.

userRouter := app.Party("/user")
{
// Use that in order to be able to register a route twice,
// last one will be executed if the previous route's handler(s) stopped and the response can be reset-ed.
// See core/router/route_register_rule_test.go#TestRegisterRuleOverlap.
userRouter.SetRegisterRule(iris.RouteOverlap)

// Authenticated is a custom type used as "annotation" for resources that requires authentication,
// its value should be the logged user ID.
type Authenticated uint64
func authDependency(ctx iris.Context, session *sessions.Session) Authenticated {
userID := session.GetUint64Default("user_id", 0)
if userID == 0 {
// If execution was stopped
// any controller's method will not be executed at all.
ctx.StopWithStatus(iris.StatusUnauthorized)
return 0
}
return Authenticated(userID)
}

userApp.Handle(new(UserController))
userApp.Handle(new(UnauthenticatedUserController))

// GetMe registers a route that will be executed when authentication is not passed
// (see UserController.GetMe) too.
func (c *UnauthenticatedUserController) GetMe() string {
return `custom action to redirect on authentication page`
}

// GetMe showcases that the same type can be used inside controller's method too,
// a second controller like `MeController` is not required.
// GET: user/me
func (c *UserController) GetMe(_ Authenticated) string {
return `UserController.GetMe: The Authenticated type
can be used to secure a controller's method too.`
}

@Dexus
Copy link
Author

Dexus commented Jun 14, 2020

Hi @kataras,

thank you, it works perfectly, just as I imagined it would. That makes things a lot easier now.

@kataras
Copy link
Owner

kataras commented Jun 14, 2020

I am glad it helped, do you think it would be easier to default this rule on mvc apps?

@Dexus
Copy link
Author

Dexus commented Jun 14, 2020

That's a good question. I think it always depends on the use case.

If I just relate it to my work and the projects I've done in the past, it might fit quite well as a default.

Just for websites with frontend I would prefer it as default. For API Entpoints, it does not always make sense.

I think a warning with debug might be helpful there depending on the setting of the SetRegisterRule. So you know why a route was not registered, but that's just a thought that would help me, because I had the problem ;)

@kataras
Copy link
Owner

kataras commented Jun 14, 2020

I think a warning with debug might be helpful there depending on the setting of the SetRegisterRule. So you know why a route was not registered, but that's just a thought that would help me, because I had the problem ;)

Yes, now this new route registration rule is described in the example too. The RouteError rule will force the app to stop with an error on duplicate routes, the RouteSkip will just silent skip duplicate, the RouteOverride (the default one) will replace the old one with the new one and RouteOverlap as described in the previous comment. So, you think it's better to add Warning messages on RouteSkip and RouteOverride? I think it's better to let it as it's, no need to depend on the logger on APIBuilder, we only return errors there. And for mvc apps we could make it default-ed, the new rule, but this may introduce hidden breaking change to existing applications, I think the updated example with this rule there it's the best possible thing for that type of things.

kataras added a commit that referenced this issue Jun 14, 2020
@Dexus
Copy link
Author

Dexus commented Jun 14, 2020

I think that's good. It's so right for me.

@Dexus
Copy link
Author

Dexus commented Jun 18, 2020

Hi @kataras

while i code for the certification, i found a crazy problem

[HTTP Server] http: panic serving 127.0.0.1:62225: reflect: Call using *controller.CustomerPrivateController as type *controller.CustomerController

Here a bit code:

// BaseController desc
type BaseController struct {
	Session       *sessions.Session
	CurrentUserID Authenticated
	Ctx           iris.Context
}

// CustomerController serves the "public" Customer API.
type CustomerController struct {
	Ctx iris.Context
}

// Get desc
// Route /category/ [GET]
func (cuc *CustomerController) Get() {
	cuc.Ctx.JSON(data)
	return
}


// CustomerPrivateController serves the "public-private" Customer API.
type CustomerPrivateController struct{ BaseController }

// Get desc
// Route /category/ [GET]
func (cupc *CustomerPrivateController) Get() *models.Category {
	return new(models.Category)
}

Do you know what is happening here?

@kataras
Copy link
Owner

kataras commented Jun 18, 2020

Hello @Dexus,

Thanks for the report! It should be fixed, update to the master one.

@kataras kataras reopened this Jun 18, 2020
@Dexus
Copy link
Author

Dexus commented Jun 19, 2020

@kataras
Thank you, works now as expected.

@Dexus
Copy link
Author

Dexus commented Jun 19, 2020

@kataras
One question, is there a way to register dependencies global, so it would not need to repeat all the registrations for each route?

@kataras
Copy link
Owner

kataras commented Jun 19, 2020

@kataras
One question, is there a way to register dependencies global, so it would not need to repeat all the registrations for each route?

Hello @Dexus,

The mvc/Application.Register registers the dependencies for all routes and controllers on that mvc Application. Do you mean for all MVC application instances? If so, then, yes you can:

https://github.com/kataras/iris/tree/master/_examples/dependency-injection

  • On mvc.New/Configure you get a new mvc Application instance for a target Party, as we already know. All dependencies from that target iris.Party are cloned and passed to that mvc Application.

  • So, if you do:

app := iris.New()
app.ConfigureContainer(func(api *iris.APIContainer){
  api.RegisterDependency(%yourdep%)
  // [...]
})

m := mvc.New(app /* or any other iris.Party */)
m.Handle(new(myController))
// no need to m.Register the %yourdep%,
// it's inherited from the target party (the root app in this case)

// The %yourdep% dependency is registered to that mvc Application
// and its controllers automatically as well.
m2 := mvc.New(app.Party("/user"))
m2.Handle(new(userController))

// [...]

@Dexus
Copy link
Author

Dexus commented Jun 19, 2020

Thanks for the reminder. I don't know why I forgot that again, use it in a project like this.

@Dexus Dexus closed this as completed Jun 19, 2020
@Dexus Dexus reopened this Jun 19, 2020
@kataras
Copy link
Owner

kataras commented Jun 19, 2020

No worries @Dexus, you can also check the database/mysql new example for some kind of "help" as well.

Also, I have just pushed another new cool feature: versioned controllers, example at: https://github.com/kataras/iris/tree/master/_examples/mvc/versioned-controller

@Dexus
Copy link
Author

Dexus commented Jun 19, 2020

Also, I have just pushed another new cool feature: versioned controllers, example at: https://github.com/kataras/iris/tree/master/_examples/mvc/versioned-controller

Thats a very cool feature!

@kataras
Copy link
Owner

kataras commented Jun 20, 2020

Yes @Dexus!

I've added another example that may be helpful for you as well: https://github.com/kataras/iris/tree/master/_examples/mvc/overview

                                         +-------------------+
                                         |  Env (DEV, PROD)  |
                                         +---------+---------+
                                         |         |         |
                                         |         |         |
                                         |         |         |
                                    DEV  |         |         |  PROD
-------------------+---------------------+         |         +----------------------+-------------------
                   |                               |                                |
                   |                               |                                |
               +---+-----+        +----------------v------------------+        +----+----+
               | sqlite  |        |         NewDB(Env) DB             |        |  mysql  |
               +---+-----+        +----------------+---+--------------+        +----+----+
                   |                               |   |                            |
                   |                               |   |                            |
                   |                               |   |                            |
      +------------+-----+     +-------------------v---v-----------------+     +----+------+
      |  greeterWithLog  |     |  NewGreetService(Env, DB) GreetService  |     |  greeter  |
      -------------+-----+     +---------------------------+-------------+     +----+------+
                   |                                       |                        |
                   |                                       |                        |
                   |           +-----------------------------------------+          |
                   |           |  GreetController          |             |          |
                   |           |                           |             |          |
                   |           |  - Service GreetService <--             |          |
                   |           |                                         |          |
                   |           +-------------------+---------------------+          |
                   |                               |                                |
                   |                               |                                |
                   |                               |                                |
                   |                   +-----------+-----------+                    |
                   |                   |      HTTP Request     |                    |
                   |                   +-----------------------+                    |
                   |                   |  /greet?name=kataras  |                    |
                   |                   +-----------+-----------+                    |
                   |                               |                                |
+------------------+--------+         +------------+------------+           +-------+------------------+
|  model.Response (JSON)    |         |  Response (JSON, error) |           |  Bad Request             |
+---------------------------+         +-------------------------+           +--------------------------+
|  {                        |                                               |  mysql: not implemented  |
|    "msg": "Hello kataras" |                                               +--------------------------+
|  }                        |
+---------------------------+

kataras added a commit that referenced this issue Jul 26, 2020
Former-commit-id: 2b5523ff3e2aab60dd83faa3c520b16a34916fbe
kataras added a commit that referenced this issue Jul 26, 2020
rel to: #1536 too


Former-commit-id: 0ed36644ee2d6c27d90450700d9241eb1ba93c17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants