![](/img/trans.png)
[英]Using a custom annotation on a Spring MVC controller method from an interceptor
[英]How to add a custom security annotation to Spring MVC controller method
我的 REST 应用程序使用 Java 8、Spring MVC 4、Spring Boot 和 Gradle。
我想通过某些 Spring MVC 4 控制器中的自定义方法注释为我的 REST 应用程序添加安全性。
这是一个基本的例子。
主控制器.java
package myapp;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
@RestController
@RequestMapping("/")
public class HomeController {
@RequestMapping("/")
public String index() {
return "<h1>Hello, World!</h1><p>Lorem Ipsum Lorem Ipsum Lorem Ipsum Lorem Ipsum Lorem Ipsum Lorem Ipsum</p>";
}
@CustomSecurityAnnotation
@RequestMapping("/secure")
public String secure() {
return "<h1>Secured!</h1><p>Lorem Ipsum Lorem Ipsum Lorem Ipsum Lorem Ipsum Lorem Ipsum Lorem Ipsum</p>";
}
}
我希望CustomSecurityAnnotation
运行一个自定义方法,该方法将检查传入 REST 请求的标头,查看 HTTP 标头Authorization
,提取提供的值(如果提供),并针对该值运行代码以在允许之前验证请求方法进行。 如果授权无效,注释应该能够覆盖响应并提供 HTTP 401 或 403,如果我决定成功传递注释自定义方法,则允许注释下的方法运行。
我意识到我可以用PreAuthorize
和其他 MVC 注释做一些类似的事情,但我正在考虑将自定义逻辑封装在单个注释内的方法中,以用于我选择的任何控制器上的任何方法。
谢谢!
我们还在我们的项目中创建了一个自定义注释。 你需要完成这个,是一些面向方面的编程。
首先,您需要创建自己的注释来标记您的方法,如下所示:
public @interface CustomSecurityAnnotation {
}
然后,您必须编写执行方法时触发的逻辑。 你为此写了一个方面。
@Aspect
@Component
public class CustomSecurityAspect {
@Pointcut("@annotation(my.package.CustomSecurityAnnotation)")
private void customSecurityAnnotation() {
}
@Around("my.package.CustomSecurityAspect.customSecurityAnnotation()")
public Object doSomething(ProceedingJoinPoint pjp) throws Throwable {
HttpServletRequest req = getRequest();
// Check header values
// Throw Spring's AccessDeniedException if needed
return pjp.proceed();
}
private HttpServletRequest getRequest() {
ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
return sra.getRequest();
}
}
如您所见,我已经包含了一种检索当前 HTTP 请求的方法,因此您可以轻松检索要检查的标头。
如果出现AccessDeniedException
,Spring 会自动将响应状态代码设置为 HTTP 403。
不要忘记在@Configuration
类上启用@EnableAspectJAutoProxy
以启用方面。
如果您不想创建自己的 Aspect(或者您想依赖普通的 Spring-Security),您可以采用 Spring Security 的机制并创建您自己的自定义SecurityExpressionRoot
如下所示: https://www.baeldung。 com/spring-security-create-new-custom-security-expression#2-custom-expression-handler
美妙的部分是您拥有框架提供的 methodInvocation ,通过反射获取您的注释并将其传递给您的CustomSecurityExpressionRoot
。 在 Kotlin 中,这看起来像这样:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
class MethodAuthConfig: GlobalMethodSecurityConfiguration() {
override fun createExpressionHandler(): MethodSecurityExpressionHandler = object: DefaultMethodSecurityExpressionHandler() {
override fun createSecurityExpressionRoot(authentication: Authentication, invocation: MethodInvocation): MethodSecurityExpressionOperations =
SecuredTargetExpressionRoot(
authentication,
// This is the important part to find your own annotation and pass it to your method security resolver
invocation.method.annotations.mapNotNull { it as? SecuredTarget }.firstOrNull()
).apply {
setThis(invocation.getThis())
setPermissionEvaluator(permissionEvaluator)
setTrustResolver(trustResolver)
setRoleHierarchy(roleHierarchy)
}
}
}
唯一缺少的是将 SpringSecurity 注释添加到您自己的注释中,例如:
@Target(FUNCTION)
@Retention(RUNTIME)
// This is the important line to let Spring security kick in action
@PreAuthorize("canAccessTarget()")
annotation class SecuredTarget (
// maybe any variables your want to specify at this annotation
)
并查看您的 Spring-Security 自定义 SpEl:
class SecuredTargetExpressionRoot(
authentication: Authentication,
private val securityInformation: SecuredTarget?
): SecurityExpressionRoot(authentication), MethodSecurityExpressionOperations {
fun canAccessTarget(): Boolean {
return // Your code of verification goes here :)
}
}
(我在我的 kotlin 项目中创建了这个。但我想你可以将这些行转换为 Java 代码没有问题。你需要做的大部分事情都在链接的教程中。我只是指出从哪里获取自定义注释信息; ) 从好的方面来说:您可以使用所有 Spring-Securitys 机制,而无需编写自己的逻辑来捕获异常等。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.