@@ -503,6 +503,126 @@ open fun findMessagesForUser(@CurrentUser customUser: CustomUser?): ModelAndView
503503----
504504======
505505
506+ Once it is a meta-annotation, parameterization is also available to you.
507+
508+ For example, consider when you have a JWT as your principal and you want to say which claim to retrieve.
509+ As a meta-annotation, you might do:
510+
511+ [tabs]
512+ ======
513+ Java::
514+ +
515+ [source,java,role="primary"]
516+ ----
517+ @Target({ElementType.PARAMETER, ElementType.TYPE})
518+ @Retention(RetentionPolicy.RUNTIME)
519+ @Documented
520+ @AuthenticationPrincipal(expression = "claims['sub']")
521+ public @interface CurrentUser {}
522+ ----
523+
524+ Kotlin::
525+ +
526+ [source,kotlin,role="secondary"]
527+ ----
528+ @Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.TYPE)
529+ @Retention(AnnotationRetention.RUNTIME)
530+ @MustBeDocumented
531+ @AuthenticationPrincipal(expression = "claims['sub']")
532+ annotation class CurrentUser
533+ ----
534+ ======
535+
536+ which is already quite powerful.
537+ But, it is also limited to retrieving the `sub` claim.
538+
539+ To make this more flexible, first publish the `AnnotationTemplateExpressionDefaults` bean like so:
540+
541+ [tabs]
542+ ======
543+ Java::
544+ +
545+ [source,java,role="primary"]
546+ ----
547+ @Bean
548+ public AnnotationTemplateExpressionDefaults templateDefaults() {
549+ return new AnnotationTemplateExpressionDeafults();
550+ }
551+ ----
552+
553+ Kotlin::
554+ +
555+ [source,kotlin,role="secondary"]
556+ ----
557+ @Bean
558+ fun templateDefaults(): AnnotationTemplateExpressionDefaults {
559+ return AnnotationTemplateExpressionDeafults()
560+ }
561+ ----
562+
563+ Xml::
564+ +
565+ [source,xml,role="secondary"]
566+ ----
567+ <b:bean name="annotationExpressionTemplateDefaults" class="org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults"/>
568+ ----
569+ ======
570+
571+ and then you can supply a parameter to `@CurrentUser` like so:
572+
573+ [tabs]
574+ ======
575+ Java::
576+ +
577+ [source,java,role="primary"]
578+ ----
579+ @Target({ElementType.PARAMETER, ElementType.TYPE})
580+ @Retention(RetentionPolicy.RUNTIME)
581+ @Documented
582+ @AuthenticationPrincipal(expression = "claims['{claim}']")
583+ public @interface CurrentUser {
584+ String claim() default 'sub';
585+ }
586+ ----
587+
588+ Kotlin::
589+ +
590+ [source,kotlin,role="secondary"]
591+ ----
592+ @Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.TYPE)
593+ @Retention(AnnotationRetention.RUNTIME)
594+ @MustBeDocumented
595+ @AuthenticationPrincipal(expression = "claims['{claim}']")
596+ annotation class CurrentUser(val claim: String = "sub")
597+ ----
598+ ======
599+
600+ This will allow you more flexibility across your set of applications in the following way:
601+
602+ [tabs]
603+ ======
604+ Java::
605+ +
606+ [source,java,role="primary"]
607+ ----
608+ @RequestMapping("/messages/inbox")
609+ public ModelAndView findMessagesForUser(@CurrentUser("user_id") String userId) {
610+
611+ // .. find messages for this user and return them ...
612+ }
613+ ----
614+
615+ Kotlin::
616+ +
617+ [source,kotlin,role="secondary"]
618+ ----
619+ @RequestMapping("/messages/inbox")
620+ open fun findMessagesForUser(@CurrentUser("user_id") userId: String?): ModelAndView {
621+
622+ // .. find messages for this user and return them ...
623+ }
624+ ----
625+ ======
506626
507627[[mvc-async]]
508628== Spring MVC Async Integration
0 commit comments