How to handle concurrency during an INSERT-SELECT cycle?
Not sure if that's the best approach, but it seems to be a quick and reliable as long as application[s] consistently uses it. 
Create a new table, access_attempt (user_id integer not null primary key).
Modify you workflow : 

begin ;
insert into attempt_access (user_id) values (:user_id);
-- do you verification, raise an error if needed
insert into access (user_id, dt) values(:user_id, current_timestamp) ;
delete from access_attempt where user_id = :user_id;
commit;  


A brief description.  First of all, a new transaction is started and we insert a user_id 
 into the new table attempt_access which has just one column. Until transaction completes , other transactions will not be able to insert row with the same user_id and will wait until the first one complete.  Then verification is performed, record insert into access table, and finally the record inserted in the very beginning is removed. Now transaction can be committed . If transaction is rolled back the record in attempt_access will be removed automatically .