用户未登录时,显示登录链接。
>>> from zope.testbrowser.wsgi import Browser
>>> skinURL = 'https://127.0.0.1/++skin++PageletTestSkin/'
>>> wsgi_app = layer.make_wsgi_app()
>>> browser = Browser(wsgi_app=wsgi_app)
>>> browser.handleErrors = False
>>> browser.open(skinURL + 'container/@@default.html')
>>> browser.url
'https://127.0.0.1/++skin++PageletTestSkin/container/@@default.html'
>>> print(browser.contents)
<!DOCTYPE ...>
<html ...>
<head>
<title>PageletTest</title>
</head>
<body>
<a href="https://127.0.0.1/++skin++PageletTestSkin/container/@@login.html?nextURL=http%3A//127.0.0.1/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">Login</a>
</body>
</html>
选择链接将导致登录页面,由于我们在此使用基本认证,我们得到HTTP错误401(未授权)。
>>> login_url = browser.getLink('Login').url
>>> browser.raiseHttpErrors = False
>>> browser.getLink('Login').click()
>>> print(browser.headers['status'])
401 Unauthorized
>>> print(browser.url)
https://127.0.0.1/++skin++PageletTestSkin/container/@@login.html?nextURL=http%3A//127.0.0.1/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html
输入正确的凭据后,我们获得授权。
>>> browser.addHeader('Authorization', 'Basic mgr:mgrpw')
>>> browser.open(browser.url)
我们被重定向到我们选择登录链接的页面。登录后,登录链接不再显示。由于我们没有指定支持登出,因此没有显示登出链接。
>>> print(browser.url)
https://127.0.0.1/++skin++PageletTestSkin/container/@@default.html
>>> print(browser.contents)
<!DOCTYPE ...>
<html ...>
<head>
<title>PageletTest</title>
</head>
<body>
</body>
</html>
再次调用登录URL将直接转到nextURL引用的页面。
>>> browser.open(login_url)
>>> print(browser.url)
https://127.0.0.1/++skin++PageletTestSkin/container/@@default.html
>>> print(browser.contents)
<!DOCTYPE ...>
<html ...>
<head>
<title>PageletTest</title>
</head>
<body>
</body>
</html>
再次调用登录URL而不带查询参数将导致一个确认页面,告知登录成功。
>>> browser.open(login_url.split('?')[0])
>>> print(browser.url)
https://127.0.0.1/++skin++PageletTestSkin/container/@@login.html
>>> print(browser.contents)
<!DOCTYPE ...>
<html ...>
<head>
<title>PageletTestLayout</title>
</head>
<body>
<div>
<h1>Login successful!</h1>
<p style="font-size: 200%"> You are now logged in as <em>Manager</em>. </p>
<a href=".">Back to the main page.</a>
</div>
</body>
</html>
选择 Back to the main page. 链接将用户送回到容器的默认视图。(ftesting.zcml 将 @@default.html 定义为默认视图。)
>>> browser.getLink('Back to the main page.').click()
>>> print(browser.url)
https://127.0.0.1/++skin++PageletTestSkin/container/
>>> print(browser.contents)
<!DOCTYPE ...>
<html ...>
<head>
<title>PageletTest</title>
</head>
<body>
</body>
</html>
提供 ILogoutSupported 适配器会导致显示登出链接。
>>> import zope.component
>>> import zope.interface
>>> import zope.authentication.logout
>>> import zope.authentication.interfaces
>>> zope.component.provideAdapter(
... zope.authentication.logout.LogoutSupported,
... adapts=[zope.interface.Interface],
... provides=zope.authentication.interfaces.ILogoutSupported)
>>> browser.reload()
>>> print(browser.url)
https://127.0.0.1/++skin++PageletTestSkin/container/
>>> print(browser.contents)
<!DOCTYPE ...>
<html ...>
<head>
<title>PageletTest</title>
</head>
<body>
<a href="https://127.0.0.1/++skin++PageletTestSkin/container/@@logout.html?nextURL=http%3A//127.0.0.1/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">Logout</a>
</body>
</html>
使用JavaScript和重定向执行登出。zope.testbrowser >= 5.0不会遵循使用meta标签的重定向。
由于testbrowser无法执行JavaScript,用户保持认证状态。
>>> logout_url = browser.getLink('Logout').url
>>> browser.getLink('Logout').click()
>>> print(browser.url)
https://127.0.0.1/++skin++PageletTestSkin/container/@@logout.html?nextURL=http%3A//127.0.0.1/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html
>>> print(browser.contents)
<!DOCTYPE ...>
<html ...>
<head>
<title>PageletTest</title>
<script type="text/javascript"><!--
// clear HTTP Authentication
...
//-->
</script>
<meta http-equiv="refresh"
content="0;url=https://127.0.0.1/++skin++PageletTestSkin/container/@@default.html" />
</head>
<body>
<a href="https://127.0.0.1/++skin++PageletTestSkin/container/@@logout.html/@@logout.html?nextURL=http%3A//127.0.0.1/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40logout.html">Logout</a>
<div>
<h1>You are being redirected!</h1>
<p style="font-size: 150%">
<a href="https://127.0.0.1/++skin++PageletTestSkin/container/@@default.html">
If you see this screen for more than 5 seconds, click here.
</a>
</p>
</div>
</body>
</html>
在登出后再次调用登出URL(使用新的浏览器实例模拟)将直接转到nextURL引用的页面。
>>> browser2 = Browser(logout_url, wsgi_app=wsgi_app)
>>> print(browser2.url)
https://127.0.0.1/++skin++PageletTestSkin/container/@@default.html
>>> print(browser2.contents)
<!DOCTYPE ...>
<html ...>
<head>
<title>PageletTest</title>
</head>
<body>
<a href="https://127.0.0.1/++skin++PageletTestSkin/container/@@login.html?nextURL=http%3A//127.0.0.1/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">Login</a>
</body>
</html>
再次调用登出URL而不带查询参数将导致一个确认页面,告知登出成功。
>>> browser2.open(logout_url.split('?')[0])
>>> print(browser2.url)
https://127.0.0.1/++skin++PageletTestSkin/container/@@logout.html
>>> print(browser2.contents)
<!DOCTYPE ...>
<html ...>
<head>
<title>PageletTest</title>
<script type="text/javascript"><!--
// clear HTTP Authentication
...
//-->
</script>
</head>
<body>
<a href="https://127.0.0.1/++skin++PageletTestSkin/container/logout.html/@@login.html?nextURL=http%3A//127.0.0.1/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40logout.html">Login</a>
<div>
<h1>Logout successful!</h1>
<p style="font-size: 200%">
You are now logged out.
</p>
<a href=".">Back to the main page.</a>
</div>
</body>
</html>
要进行Cookie认证,我们首先必须设置一个可插拔认证工具(PAU)和一个认证插件(主体文件夹)。
>>> from zope.authentication.interfaces import IAuthentication
>>> from zope.pluggableauth.interfaces import IAuthenticatorPlugin
>>> from zope.pluggableauth.authentication import PluggableAuthentication
>>> from zope.pluggableauth.plugins.principalfolder import PrincipalFolder
>>> from zope.site import site
>>> root = layer.getRootFolder()
>>> root['principal_folder'] = PrincipalFolder()
>>> sm = root.getSiteManager()
>>> sm.registerUtility(
... root['principal_folder'], IAuthenticatorPlugin, 'principal_folder')
>>> root['auth'] = PluggableAuthentication()
>>> sm.registerUtility(root['auth'], IAuthentication, '')
>>> root['auth'].credentialsPlugins = (u'Session Credentials',)
>>> root['auth'].authenticatorPlugins = (u'principal_folder',)
我们需要主体文件夹内的一个主体。
>>> from zope.pluggableauth.plugins.principalfolder import InternalPrincipal
>>> root['principal_folder']['1'] = InternalPrincipal(
... 'tester', 'tpass', 'Tester')
我们使用一个新的浏览器,因此主体未登录,显示登录链接。
>>> browser = Browser(wsgi_app=wsgi_app)
>>> browser.open(skinURL + 'container/@@default.html')
>>> print(browser.url)
https://127.0.0.1/++skin++PageletTestSkin/container/@@default.html
>>> print(browser.contents)
<!DOCTYPE ...>
<html ...>
<head>
<title>PageletTest</title>
</head>
<body>
<a href="https://127.0.0.1/++skin++PageletTestSkin/container/@@login.html?nextURL=http%3A//127.0.0.1/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">Login</a>
</body>
</html>
选择链接将导致登录页面。
>>> login_url = browser.getLink('Login').url
>>> browser.getLink('Login').click()
>>> print(browser.url)
https://127.0.0.1/++skin++PageletTestSkin/@@loginForm.html?camefrom=http%3A%2F%2Flocalhost%2F%2B%2Bskin%2B%2BPageletTestSkin%2Fcontainer%2F%40%40login.html%3FnextURL%3Dhttp%253A%2F%2Flocalhost%2F%252B%252Bskin%252B%252BPageletTestSkin%2Fcontainer%2F%2540%2540default.html
>>> print(browser.contents)
<!DOCTYPE ...>
<html ...>
<head>
<title>PageletTestLayout</title>
</head>
<body>
<div>
<p>
Please provide Login Information
</p>
<form action="" method="post">
<div class="row">
<div class="label"><label for="login">User Name</label></div>
<div class="field">
<input type="text" name="login" id="login" />
</div>
</div>
<div class="row">
<div class="label"><label for="password">Password</label></div>
<div class="field">
<input type="password" name="password" id="password" />
</div>
</div>
<div class="row">
<input class="form-element" type="submit"
name="SUBMIT" value="Log in" />
</div>
<input type="hidden" name="camefrom" value="https://127.0.0.1/++skin++PageletTestSkin/container/@@login.html?nextURL=http%3A//127.0.0.1/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">
</form>
</div>
</body>
</html>
输入错误的用户名不会授权,但会显示错误消息。
>>> browser.getControl('User Name').value = 'me'
>>> browser.getControl('Password').value = 'tpass'
>>> browser.getControl('Log in').click()
>>> print(browser.url)
https://127.0.0.1/++skin++PageletTestSkin/@@loginForm.html?camefrom=http%3A%2F%2Flocalhost%2F%2B%2Bskin%2B%2BPageletTestSkin%2Fcontainer%2F%40%40login.html%3FnextURL%3Dhttp%253A%2F%2Flocalhost%2F%252B%252Bskin%252B%252BPageletTestSkin%2Fcontainer%2F%2540%2540default.html
>>> print(browser.contents)
<!DOCTYPE ...>
<html ...>
<head>
<title>PageletTestLayout</title>
</head>
<body>
<div>
<p>
Please provide Login Information
</p>
<form action="" method="post">
<div class="row">
<div class="label"><label for="login">User Name</label></div>
<div class="field">
<input type="text" name="login" id="login" />
</div>
</div>
<div class="row">
<div class="label"><label for="password">Password</label></div>
<div class="field">
<input type="password" name="password" id="password" />
</div>
</div>
<div class="row">
<input class="form-element" type="submit"
name="SUBMIT" value="Log in" />
</div>
<input type="hidden" name="camefrom" value="https://127.0.0.1/++skin++PageletTestSkin/container/@@login.html?nextURL=http%3A//127.0.0.1/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">
</form>
</div>
</body>
</html>
输入错误的密码也不会授权。
>>> browser.getControl('User Name').value = 'tester'
>>> browser.getControl('Password').value = 'let me in'
>>> browser.getControl('Log in').click()
>>> print(browser.url)
https://127.0.0.1/++skin++PageletTestSkin/@@loginForm.html?camefrom=http%3A%2F%2Flocalhost%2F%2B%2Bskin%2B%2BPageletTestSkin%2Fcontainer%2F%40%40login.html%3FnextURL%3Dhttp%253A%2F%2Flocalhost%2F%252B%252Bskin%252B%252BPageletTestSkin%2Fcontainer%2F%2540%2540default.html
>>> print(browser.contents)
<!DOCTYPE ...>
<html ...>
<head>
<title>PageletTestLayout</title>
</head>
<body>
<div>
<p>
Please provide Login Information
</p>
<form action="" method="post">
<div class="row">
<div class="label"><label for="login">User Name</label></div>
<div class="field">
<input type="text" name="login" id="login" />
</div>
</div>
<div class="row">
<div class="label"><label for="password">Password</label></div>
<div class="field">
<input type="password" name="password" id="password" />
</div>
</div>
<div class="row">
<input class="form-element" type="submit"
name="SUBMIT" value="Log in" />
</div>
<input type="hidden" name="camefrom" value="https://127.0.0.1/++skin++PageletTestSkin/container/@@login.html?nextURL=http%3A//127.0.0.1/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">
</form>
</div>
</body>
</html>
输入正确的用户名和密码后,用户获得授权。
>>> browser.getControl('User Name').value = 'tester'
>>> browser.getControl('Password').value = 'tpass'
>>> browser.getControl('Log in').click()
用户被重定向到他选择登录链接的页面。登录后,登录链接不再显示。由于我们已指定支持登出,因此会显示登出链接。
>>> print(browser.url)
https://127.0.0.1/++skin++PageletTestSkin/container/@@default.html
>>> print(browser.contents)
<!DOCTYPE ...>
<html ...>
<head>
<title>PageletTest</title>
</head>
<body>
<a href="https://127.0.0.1/++skin++PageletTestSkin/container/@@logout.html?nextURL=http%3A//127.0.0.1/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">Logout</a>
</body>
</html>
再次调用登录URL将直接转到nextURL引用的页面。
>>> browser.open(login_url)
>>> print(browser.url)
https://127.0.0.1/++skin++PageletTestSkin/container/@@default.html
>>> print(browser.contents)
<!DOCTYPE ...>
<html ...>
<head>
<title>PageletTest</title>
</head>
<body>
<a href="https://127.0.0.1/++skin++PageletTestSkin/container/@@logout.html?nextURL=http%3A//127.0.0.1/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">Logout</a>
</body>
</html>
再次调用登录URL而不带查询参数将导致一个确认页面,告知登录成功。
>>> browser.open(login_url.split('?')[0])
>>> print(browser.url)
https://127.0.0.1/++skin++PageletTestSkin/container/@@login.html
>>> print(browser.contents)
<!DOCTYPE ...>
<html ...>
<head>
<title>PageletTestLayout</title>
</head>
<body>
<div>
<h1>Login successful!</h1>
<p style="font-size: 200%"> You are now logged in as <em>Tester</em>. </p>
<a href=".">Back to the main page.</a>
</div>
</body>
</html>
选择 Back to the main page. 链接将用户送回到容器的默认视图。(ftesting.zcml 将 @@default.html 定义为默认视图。)
>>> browser.getLink('Back to the main page.').click()
>>> print(browser.url)
https://127.0.0.1/++skin++PageletTestSkin/container/
>>> print(browser.contents)
<!DOCTYPE ...>
<html ...>
<head>
<title>PageletTest</title>
</head>
<body>
<a href="https://127.0.0.1/++skin++PageletTestSkin/container/@@logout.html?nextURL=http%3A//127.0.0.1/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">Logout</a>
</body>
</html>
选择显示的登出链接将删除认证信息并显示一个确认页面,该页面将重定向到默认页面,其中再次显示登录链接。
>>> logout_url = browser.getLink('Logout').url
>>> browser.getLink('Logout').click()
>>> print(browser.contents)
<!DOCTYPE ...>
<html ...>
<head>
<title>PageletTest</title>
<script type="text/javascript"><!--
// clear HTTP Authentication
...
//-->
</script>
<meta http-equiv="refresh"
content="0;url=https://127.0.0.1/++skin++PageletTestSkin/container/@@default.html" />
</head>
<body>
<a href="https://127.0.0.1/++skin++PageletTestSkin/container/@@logout.html/@@logout.html?nextURL=http%3A//127.0.0.1/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40logout.html">Logout</a>
<div>
<h1>You are being redirected!</h1>
<BLANKLINE>
<p style="font-size: 150%">
<a href="https://127.0.0.1/++skin++PageletTestSkin/container/@@default.html">
If you see this screen for more than 5 seconds, click here.
</a>
</p>
</div>
</body>
</html>
>>> browser.getLink('If you see this screen for more than 5 seconds').click()
>>> print(browser.contents)
<!DOCTYPE ...>
<html ...>
<head>
<title>PageletTest</title>
</head>
<body>
<a href="https://127.0.0.1/++skin++PageletTestSkin/container/@@login.html?nextURL=http%3A//127.0.0.1/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">Login</a>
</body>
</html>
登出后再次调用登出URL将直接转到nextURL引用的页面。
>>> browser.open(logout_url)
>>> print(browser.url)
https://127.0.0.1/++skin++PageletTestSkin/container/@@default.html
>>> print(browser.contents)
<!DOCTYPE ...>
<html ...>
<head>
<title>PageletTest</title>
</head>
<body>
<a href="https://127.0.0.1/++skin++PageletTestSkin/container/@@login.html?nextURL=http%3A//127.0.0.1/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">Login</a>
</body>
</html>
再次调用登出URL而不带查询参数将导致一个确认页面,告知登出成功。
>>> browser.open(logout_url.split('?')[0])
>>> print(browser.url)
https://127.0.0.1/++skin++PageletTestSkin/container/@@logout.html
>>> print(browser.contents)
<!DOCTYPE ...>
<html ...>
<head>
<title>PageletTest</title>
<script type="text/javascript"><!--
// clear HTTP Authentication
...
//-->
</script>
</head>
<body>
<a href="https://127.0.0.1/++skin++PageletTestSkin/container/logout.html/@@login.html?nextURL=http%3A//127.0.0.1/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40logout.html">Login</a>
<div>
<h1>Logout successful!</h1>
<p style="font-size: 200%">
You are now logged out.
</p>
<a href=".">Back to the main page.</a>
</div>
</body>
</html>
如果参数 camefrom 使用了两次,则实际上只使用了第一个。
>>> browser.open('https://127.0.0.1/++skin++PageletTestSkin/@@loginForm.html?camefrom=first-url&camefrom=second-url')
>>> print(browser.contents)
<!DOCTYPE ...>
...
<div class="row">
<input class="form-element" type="submit" name="SUBMIT" value="Log in" />
</div>
<input type="hidden" name="camefrom" value="first-url">
</form>
</div>
</body>
</html>
>>> 'second-url' in browser.contents
False