Hello mate, the last time I had to do something like this in version 3 I had to implement this logic manually 
However, as I am a bad programmer and this usecase seems to be very common and important, I would be VERY interested if there are better ways to implement the owner policy.
Here is an example what I did for my content type survey:
async findOne(ctx) {
const { id } = ctx.params;
const { user } = ctx.state;
const entity = await strapi.services.survey.findOne({ id });
const interviewees = entity.interviewees;
let survey = sanitizeEntity(entity, { model: strapi.models.survey });
// if the request is made by an authenticated user and the authenticated user
// does not match the survey author then return error
if (user && user.id != survey.survey_author.id) {
ctx.throw(403, 'You are not allowed to access the information');
return
}
// if the request is not made by an authenticated user check if user belongs to
// survey interviewee and if so return non sensitive survey data
if (!user) {
const cValue = await strapi.services.user.cookieValue(ctx);
// if provided cookie value is not valid return error
if (!identifierExists(interviewees, cValue)) {
ctx.throw(403, 'Provide a correct surveycode');
return
} else {
// if provided cookie value is valid delete sensitive survey data
delete survey.survey_author;
delete survey.interviewees;
}
}
// default case return all survey information
return survey
}