fallback for method based authorization
Junhyunny opened this issue · comments
I am following an example in the spring security document to handle fallback for method based authorization.
In this example, @HandleAuthorizationDenied
annotation is on the POJO User class's getEmail method like this.
public class User {
// ...
@PostAuthorize(value = "hasAuthority('user:read')")
@HandleAuthorizationDenied(handlerClass = EmailMaskingMethodAuthorizationDeniedHandler.class)
public String getEmail() {
return this.email;
}
}
This is not working in my test code. Here is my codes.
User class
package com.example.demo.domain;
import com.example.demo.handler.EmailMaskingMethodAuthorizationDeniedHandler;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.authorization.method.HandleAuthorizationDenied;
public class User {
private final String email;
public User(String email) {
this.email = email;
}
@PostAuthorize(value = "hasAuthority('USER::READ')")
@HandleAuthorizationDenied(handlerClass = EmailMaskingMethodAuthorizationDeniedHandler.class)
public String getEmail() {
return email;
}
}
UserService class
package com.example.demo.service;
import com.example.demo.domain.User;
import org.springframework.stereotype.Service;
@Service
public class UserService {
public User getUser() {
return new User("junhyunny@naver.com");
}
}
UserServiceTests class
package com.example.demo;
import com.example.demo.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class UserServiceTests {
@Autowired
UserService sut;
@Test
void test() {
var result = sut.getUser();
System.out.println(result.getEmail());
}
}
Result is this.
junhyunny@naver.com
Is there a something what I miss? Please let me know. Is it working well? I tried this example with spring data jpa because I doubted that there are some mechanism working together with jpa repository. However the trial with jpa was also failed.
I think that @PostAuthorize
annotation is working based on Spring AOP, so we need to this annotation should be on the UserService bean's getUser method.
Like this.
@Service
public class UserService {
@PostAuthorize(value = "hasAuthority('USER::READ')")
@HandleAuthorizationDenied(handlerClass = EmailMaskingMethodAuthorizationDeniedHandler.class)
public User getUser() {
return new User("junhyunny@naver.com");
}
}
And MethodAuthorizationDeniedHandler instance is changed like this.
@Component
public class EmailMaskingMethodAuthorizationDeniedHandler implements MethodAuthorizationDeniedHandler {
@Override
public Object handleDeniedInvocation(MethodInvocation methodInvocation, AuthorizationResult authorizationResult) {
return "***";
}
@Override
public Object handleDeniedInvocationResult(MethodInvocationResult methodInvocationResult, AuthorizationResult authorizationResult) {
User user = (User) methodInvocationResult.getResult(); // get user
return new User(user.getEmail().replaceAll("(^[^@]{3}|(?!^)\\G)[^@]", "$1*")); // return new user instance
}
}
When I changed the code like above. Test result is this.
jun******@naver.com
The example in the document is wrong or not? If sample code in the example is wrong, can I change like this?
Hi @Junhyunny, thanks for the report. Yes, the feature relies on Spring AOP. The documentation says:
Let’s consider the example from the previous section
The previous section uses @AuthorizeReturnObject
in the service class, effectively generating a proxy for the User
class. Can you try adding the annotation and see if it works?
Great! It is worked. Thanks, I am going to close this issue.