Index: docs/topics/auth.txt
===================================================================
--- docs/topics/auth.txt	(revision 16345)
+++ docs/topics/auth.txt	(working copy)
@@ -1156,6 +1156,10 @@
     ``"<app label>.<permission codename>"`` (i.e. ``polls.can_vote`` for a
     permission on a model in the ``polls`` application).
 
+    If the user is *not* logged in, he will be redirected to the ``login_url``.
+    If the user *is* logged in but doesn't have permission, a 403 error response
+    (forbidden) will be returned. See :doc:`/topics/http/views/`.
+
     Note that :func:`~django.contrib.auth.decorators.permission_required()`
     also takes an optional ``login_url`` parameter. Example::
 
Index: tests/modeltests/test_client/models.py
===================================================================
--- tests/modeltests/test_client/models.py	(revision 16345)
+++ tests/modeltests/test_client/models.py	(working copy)
@@ -364,9 +364,9 @@
         login = self.client.login(username='testclient', password='password')
         self.assertTrue(login, 'Could not log in')
 
-        # Log in with wrong permissions. Should result in 302.
+        # Log in with wrong permissions. Should result in 403.
         response = self.client.get('/test_client/permission_protected_view/')
-        self.assertRedirects(response, 'http://testserver/accounts/login/?next=/test_client/permission_protected_view/')
+        self.assertEqual(response.status_code, 403)
 
         # TODO: Log in with right permissions and request the page again
 
@@ -381,9 +381,9 @@
         login = self.client.login(username='testclient', password='password')
         self.assertTrue(login, 'Could not log in')
 
-        # Log in with wrong permissions. Should result in 302.
+        # Log in with wrong permissions. Should result in 403.
         response = self.client.get('/test_client/permission_protected_method_view/')
-        self.assertRedirects(response, 'http://testserver/accounts/login/?next=/test_client/permission_protected_method_view/')
+        self.assertEqual(response.status_code, 403)
 
         # TODO: Log in with right permissions and request the page again
 
Index: tests/regressiontests/comment_tests/tests/moderation_view_tests.py
===================================================================
--- tests/regressiontests/comment_tests/tests/moderation_view_tests.py	(revision 16345)
+++ tests/regressiontests/comment_tests/tests/moderation_view_tests.py	(working copy)
@@ -80,7 +80,7 @@
         pk = comments[0].pk
         self.client.login(username="normaluser", password="normaluser")
         response = self.client.get("/delete/%d/" % pk)
-        self.assertEqual(response["Location"], "http://testserver/accounts/login/?next=/delete/%d/" % pk)
+        self.assertEqual(response.status_code, 403)
 
         makeModerator("normaluser")
         response = self.client.get("/delete/%d/" % pk)
@@ -124,7 +124,7 @@
         pk = comments[0].pk
         self.client.login(username="normaluser", password="normaluser")
         response = self.client.get("/approve/%d/" % pk)
-        self.assertEqual(response["Location"], "http://testserver/accounts/login/?next=/approve/%d/" % pk)
+        self.assertEqual(response.status_code, 403)
 
         makeModerator("normaluser")
         response = self.client.get("/approve/%d/" % pk)
Index: django/contrib/auth/decorators.py
===================================================================
--- django/contrib/auth/decorators.py	(revision 16345)
+++ django/contrib/auth/decorators.py	(working copy)
@@ -2,6 +2,7 @@
 from functools import wraps
 from django.conf import settings
 from django.contrib.auth import REDIRECT_FIELD_NAME
+from django.core.exceptions import PermissionDenied
 from django.utils.decorators import available_attrs
 
 
@@ -50,6 +51,14 @@
 def permission_required(perm, login_url=None):
     """
     Decorator for views that checks whether a user has a particular permission
-    enabled, redirecting to the log-in page if necessary.
+    enabled, redirecting to the log-in page if user is not authenticated.
+    If user is authenticated and does not have the permission, raise
+    PermissionDenied.
     """
-    return user_passes_test(lambda u: u.has_perm(perm), login_url=login_url)
+    def check_perms(user):
+        if user.is_anonymous():
+            return False
+        if user.has_perm(perm):
+            return True
+        raise PermissionDenied
+    return user_passes_test(check_perms, login_url=login_url)
