I don't want to handle the boolean in the outer function. I want the outer function execution to stop by the inner function. In this way, I can sprinkle this function anywhere in the paclet and perform verification in different places without modifying the code of main functions.
When you "sprinkle" the auth function in, you'll be modifying the code of the other functions. A better way would be to keep the domain functions clean of any authentication and apply authentication to them in a way that they remain completely ignorant. If you add an "inner function", then they are still being disrupted.
So, you might want to try something along these lines. Create a function that can be applied to another symbol before the other symbol is allowed to operate on its arguments.
RequireAuth[method_, userdata_][func_] :=
If[method[userdata], func, AuthFailure[func, method, userdata]]
I'm just thinking ahead here and generalizing a bit, but you could forgo method
and userdata
and just implicitly do the check you were already doing. Let's test it.
RequireAuth[True &, {"name", "password"}][Sin][0]
(* 0 *)
RequireAuth[False &, {"name", "password"}][Sin][0]
(* AuthFailure[Sin, False &, {"name", "password"}][0] *)
I'm hinting that one authentication method might be username + password, but the userdata
for these tests is just ignored.
Now, I used that AuthFailure
expression as a placeholder, but we'd actually like it to do something useful, so let's give it some behavior.
AuthFailure[func_, method_, userdata_][args___] :=
Failure[
"AuthenticationFailure",
<|"MessageTemplate" -> "Authentication failed (`Method`) for user `UserData` at `Function` with arguments `Arguments`",
"MessageParameters" -> <|"Method" -> method, "UserData" -> userdata, "Function" -> func, "Arguments" -> {args}|>|>]
Now if you re-evaluate our tests, you'll see a Failure
object for one of them. For testing purposes, we might want some helpers.
TestAuthPass[___] := True;
TestAuthFail[___] := False;
And we can write our tests like this:
RequireAuth[TestAuthPass, {"name", "password"}][Sin][0]
RequireAuth[TestAuthFail, {"name", "password"}][Sin][0]
Now, wherever you're using a domain-specific function (say Abc
) that you want to guard with authentication, you just replace that symbol with RequireAuth[...auth stuff...][Abc]
. Of course, there are programmatic ways to do that also.
This is really intended to demonstrate a general strategy. Without knowing any more context, I don't really expect my exact implementation here to work perfectly for you.
VerifyUserPermission[...]
returnTrue
orFalse
depending if verified or not, then the caller decides what to do based on this? I do not understand what is the main issue here. $\endgroup$Block
if there is no easy answer. How to useReturn
in the inner function and apply it to the outer function from the inner function? orAbort
is the only option I have? $\endgroup$