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

Access the impl in interceptor #1370

Closed
wenerme opened this issue Dec 18, 2024 · 1 comment
Closed

Access the impl in interceptor #1370

wenerme opened this issue Dec 18, 2024 · 1 comment
Labels
enhancement New feature or request

Comments

@wenerme
Copy link

wenerme commented Dec 18, 2024

Is your feature request related to a problem? Please describe.

I want to access the metadata for the impl from interceptor, seems this is impossible.

I want to get the spec.impl, it's even better to allowed access the service impl givend by router.service

export async function invokeUnaryImplementation<
I extends DescMessage,
O extends DescMessage,
>(
spec: MethodImplSpec<I, O> & { kind: "unary" },
context: HandlerContext,
input: MessageShape<I>,
interceptors: Interceptor[],
): Promise<MessageShape<O>> {
const anyFn = async (
req: UnaryRequest<I, O>,
): Promise<UnaryResponse<I, O>> => {
return {
message: normalize(
spec.method.output,
await spec.impl(req.message, mergeRequest(context, req)),
),
stream: false,
method: spec.method,
...responseCommon(context, spec),
};
};
const next = applyInterceptors(anyFn, interceptors);
const { message, header, trailer } = await next({
stream: false,
message: input,
method: spec.method,
...requestCommon(context, spec),
});
copyHeaders(header, context.responseHeader);
copyHeaders(trailer, context.responseTrailer);
return message;
}

Describe the solution you'd like

maybe allowed to change the spec.impl or put some magic in contextValues ?

Describe alternatives you've considered

give a proxy object for router.service, return warped func there

Additional context

For opt-in case, I have to add decorator for all methods, I hope I can do opt-out by check the auth in interceptor instead wrap the method when decorate.

@Auth()
class UserServiceImpl {
@AuthZ({})
 list(){
}
}


function getAuthZMeta(){
}
@wenerme wenerme added the enhancement New feature or request label Dec 18, 2024
@srikrsna-buf
Copy link
Member

While it may seem like a trivial change to expose the implementation, it will open a whole new way of interacting with the router that could have unintended consequences.

For the opt-out cases there are a couple of ways to solve this:

  1. Use an interceptor that accepts an exclude list for bypassing the authentication:
import type { DescMethod } from "@bufbuild/protobuf";
import type { Interceptor } from "@connectrpc/connect";

export function createAuthInterceptor(exclude: DescMethod[]): Interceptor {
const excludeSet = new Set(exclude.map((m) => `${m.parent.typeName}/${m.name}`))
return (next) => {
  return async (req) => {
    if (excludeSet.has(`${req.service.typeName}/${req.method.name}`)) {
      // Authentication logic
    }
    return await next(req);
  };
};
}

This way the default is to authenticate and you can opt-out of authentication. If you prefer colocation, you can use decorators
to modify a global exclude list (I wouldn't recommend doing that).

  1. Protobuf options can be used to address this problem. You can decorate RPCs with metadata that can be retrieved in an interceptor. There are several projects that use such techniques, one such project is protovalidate. Although it uses options for fields and message, the techniques and process is similar to methods.

I'd suggest starting with option 1 as that is the simplest and most straightforward, as the project's needs change you can evaluate option 2 and implement it if and when needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants