我在我的应用程序中使用spring security并遇到了问题。我的应用程序有一个Update Profile
页面。我已将preAuthorized()与请求映射添加为
@PreAuthorize("isAuthenticated()")
@RequestMapping (value="/user/{uid}/profile/update", method = GET)
public String updateProfileView(@ModelAttribute("form") UserProfileForm form, @PathVariable ("uid") Integer userId, Model model){
工作正常,unauthenticated
用户无法访问此页面。
但问题在于every Authenticated User can access this page
。
例如:用户A登录到应用程序后,他/她将能够更新每个人的个人资料。
我的CustomUserDetailService类是
@Service
@Transactional
public class CustomUserDetailsService implements UserDetailsService {
@Resource
UserService userService;
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
com.analyst.future.domain.User user = userService.getUser(email);
SimpleGrantedAuthority auth = new SimpleGrantedAuthority("ROLE_USER");
Collection<SimpleGrantedAuthority> authorities = new HashSet<SimpleGrantedAuthority>();
authorities.add(auth);
User userDeatails = new User(user.getEmail(), user.getPassword(), authorities);
return userDeatails;
}
}
我认为我不能用roles
来限制它,因为每个经过身份验证的用户都会有相同的角色。
我是否可以限制经过身份验证的用户仅访问自update profile
页。
答案 0 :(得分:1)
我不是Spring安全专家,但尝试阅读使用基于表达式的访问 - Link here
有一条很小的小线符合你想要的 -
例如,如果您希望某个特定方法仅允许访问其用户名与联系人的用户名匹配的用户,则可以编写
@PreAuthorize("#contact.name == authentication.name") public void doSomething(Contact contact);
我认为在你的情况下它会像
@PreAuthorize("email == authentication.email")
这是方法级别,所以也许不是你想要的?好消息是有一种方法可以使用登录用户并将其与请求用户进行匹配。 :)
答案 1 :(得分:0)
由于之前的所有答案都讨论匹配用户名(包含在主体对象中),但您需要匹配用户 ID,因此需要做更多工作。我们首先需要返回一个扩展 UserDetails
的自定义 User 对象。您可以这样做:
UserDetails
@Entity
public class UserAccount implements UserDetails {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@JsonProperty("id")
private int userId;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
private String email;
private String password;
// other fields and methods
}
您还必须覆盖 UserDetails
中的一些方法,这很容易弄清楚。
UserDetailsService
@Component
public class UserAccountService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) {
// todo
}
}
loadUserByUsername
方法返回您的用户模型@Override
public UserDetails loadUserByUsername(String username) {
Optional<UserAccount> userAccount = userAccountDao.findByEmail(username);
if (!userAccount.isPresent()) {
throw new MyException("User account not found for the given Username.", HttpStatus.NOT_FOUND);
}
return userAccount.get();
}
@PreAuthorize
表达式添加到您的资源中@PutMapping(value = "/{userId}")
@PreAuthorize("#userId == authentication.principal.userId or hasAuthority('ADMIN')")
public UserAccount updateUserAccount(@PathVariable("userId") int userId,
@RequestBody UserAccount userAccount) {
return userAccountService.updateUserAccount(userId, userAccount);
}
上面需要注意的重要事项是:
我们可以检查上面的 userId 是否相等,因为我们的自定义 UserAccount
模型有一个 userId。如果我们返回了一个原始的 UserDetail
(如 org.springframework.security.core.userdetails.User
)对象,它不会有任何 'id' 属性与之匹配,所以上面会失败。
以上 @PreAuthorize
注释检查 2 个条件。它允许请求如果用户是帐户的所有者或如果用户具有管理员权限。< /p>