Scratched my head quite a bit on this since its a tough problem to solve with Web Parts. I haven't tried out what I outline below - but from looking at the code I *think* it will work.
Try deriving from SqlPersonalizationProvider, and overriding the LoadPersonalizationBlobs method. The trick here is along the lines of what you are suggesting - you need to make the personalization system think it is loading the shared scope data for a page, but instead you want to return the per-user data for a specific user. The reason for deriving from SqlPersonalizationProvider is so you can fake out the personalization stack.
For LoadPersonlizationBlobs, you want the override to return the per-user data even though it is being asked to load shared state. You will have to fill in a non-null value for the username parameter - the value will be the user whose personalized data you want to retrieve. Than call base.LoadPersonalizationBlobs. When the call returns, you should have a null value for the sharedDataBlob (assuming that no one ever set shared state for the page) and a non-null value for the userDataBlob. Swap those values around - so that your custom provider returns the userDataBlob from the base provider in the sharedDataBlob parameter. And the null value is instead returned in the userDataBlob parameter.
This should have the effect of making the personalization stack think it just retrieved the shared data for the page, when in reality it now has the personalized data of the page for a specific user.
-Stefan
----------------------------------------------------------
This posting is provided "AS IS" with no warranties, and confers no rights.