XRX/使用者管理
您想管理網站使用者的組,驗證他們在網站上的角色,並跟蹤依賴於使用者的相關資訊。此應用程式將管理使用者列表,並將使用者的登入嘗試次數,會話超時間隔以及分配給他們的角色相關聯。
我們的應用程式將使用基於角色的訪問控制 (RBAC)。我們將使用幾個函式來執行使用者管理。
xmldb:login($collection, $user, $pass) will log the user into the system and verify they have write access to a collection.
注意,要登出使用者,我們將登入更改為使用者“guest”。
xmldb:get-current-user() will return the user-id of the current user.
我們還需要新增一個新函式來檢查給定使用者是否具有某個角色。
auth:has-role(xmldb:get-current-user(), $role) as xs:boolean check to see if a user has a given role.
如果當前使用者具有給定角色,這將返回true()。
以下是一個使用者資訊的示例。請注意,我們不會將密碼儲存在此檔案中。eXist 系統用於儲存使用者的密碼。
<user>
<id>47</id>
<user-id>jdoe</user-id>
<person-given-name>John</person-given-name>
<person-family-name>Doe</person-family-name>
<account-active-indicator>true</account-active-indicator>
<max-login-retrys>5</max-login-retrys>
<session-timeout-minutes>60</session-timeout-minutes>
<roles>
<role>ba</role>
<role>ba-admin</role>
</roles>
</user>
在上面的示例中,使用者jdoe的角色是ba和ba-admin,這意味著該使用者被歸類為業務分析師,並且還具有管理系統中業務分析師工具的能力。
因此,以下函式
auth:has-role('jdoe', 'ba')
將返回true()
以下是一個簡化的登入表單,允許使用者輸入登入名和密碼並執行 HTTP POST 操作。請注意,這與 eXist 標準登入不同,因為它不會使用 HTTP get 將密碼放在 URL 上。此資訊放置在日誌檔案中可能會損害系統的安全性。
xquery version "1.0";
import module namespace style ='http://code.google.com/p/xrx/style' at '/db/xrx/modules/style.xqm';
declare option exist:serialize "method=xhtml media-type=text/html indent=yes";
let $user := xmldb:get-current-user()
(: this gets the entire input URL :)
let $get-query-string := request:get-query-string()
(: were are only interested in the portion after the return= :)
let $return-uri := substring-after($get-query-string, 'return=')
return
<html>
<head>
<title>Login</title>
{style:import-css()}
</head>
<body>
{style:header()}
<h1>Login</h1>
<p>Current User = {$user}</p>
<form action="login.xq" method="post">
<table class="login" cellpadding="5">
<tr>
<th colspan="2" align="left">Please Login</th>
</tr>
<tr>
<td align="left">Username:</td>
<td><input name="user" type="text" size="20"/></td>
</tr>
<tr>
<td align="left">Password:</td>
<td><input name="pass" type="password" size="20"/></td>
</tr>
</table>
<input name="return" type="hidden" value="{$return-uri}" size="20"/>
<input type="submit" value="Login"/>
</form>
<p>We will return to the following URI on success: {$return-uri}</p>
{style:footer()}
</body>
</html>
以下指令碼從 HTTP POST 操作獲取傳入的登入資料並執行登入。HTTP POST 資料從以下鍵值對格式的request:get-data()格式到達
user=jdoe&pass=mypass&return=/exist/rest/db/xrx/apps/test/view/view-item.xq&id=47
請注意,我們假設user-id在第一個鍵值對中,pass在第二個鍵值對中。如果您想要更通用的介面,則可以在所有傳入的表單鍵值對中掃描正確的鍵。
xquery version "1.0";
import module namespace style ='http://code.google.com/p/xrx/style' at '/db/xrx/modules/style.xqm';
declare option exist:serialize "method=xhtml media-type=text/html indent=yes";
let $data := request:get-data()
let $tokens := tokenize($data, '&')
let $user := substring-after($tokens[1], 'user=')
let $pass := substring-after($tokens[2], 'pass=')
let $return := substring-after($tokens[3], 'return=')
(: this is required to fix the incomming URI encodings :)
let $unescape-uri := request:unescape-uri($return, 'UTF-8')
(: this is required to put the first parameter deliminator ? back in place of the ampersand :)
let $fix-first-param := replace($unescape-uri, 'xq&', 'xq?')
let $login-success-indicator := xmldb:login("/db", $user, $pass)
return
<html>
<head>
<title>Login Result</title>
{style:import-css()}
</head>
<body>
{style:header()}
{style:breadcrumb()}
<h1>Login Status</h1>
{if ($login-success-indicator)
then <p>Your Login Was Successful <a href="{$fix-first-param}">Return</a></p>
else <p>Login Failed <a href="login-form.xq">Try Again</a></p>
}
You are logged in to the root database collection as {xmldb:get-current-user()}
<br/>
<a href="logout.xq">Logout</a>
{style:footer()}
</body>
</html>
以下指令碼將您登出系統。從技術上講,它只是將您登入為具有隻讀訪問許可權的使用者。
xquery version "1.0";
import module namespace style='http://mdr.crossflow.com/style' at '/db/crossflo/modules/style.xq';
declare option exist:serialize "method=xhtml media-type=text/html indent=yes";
let $null := xmldb:login("/db", "guest", "guest")
let $user := xmldb:get-current-user()
return
<html>
<head>
<title>Logout</title>
{style:import-css()}
{style:breadcrumb()}
</head>
<body>
{style:header()}
<h1>You have been logged out.</h1>
<p>User = {$user}</p>
<a href="login-form.xq">Login</a>
{style:footer()}
</body>
</html
現在我們將建立一個執行給定使用者的身份驗證檢查的 XQuery 模組。
許多螢幕都有指向編輯表單的連結,允許使用者更改資料。您可以透過將以下程式碼新增到通常具有編輯連結的每個頁面來有條件地顯示這些編輯連結
{if (auth:has-role(xmldb:get-current-user(), 'ba'))
then
<div>
<a href="../edit/edit.xq?id={$id}">Edit Item</a>
<a href="../edit/delete-confirm.xq?id={$id}">Delete Item</a>
</div>
else
<span>User {xmldb:get-current-user()} has no roles with edit privileges
<a href="{auth:login-uri()}">Login</a>
</span>
}
您還可以在具有敏感資訊或功能的任何頁面中新增一個函式,方法是檢查使用者是否已登入。這可以透過一個名為 auth:validate-user() 的函式完成。
request:get-session-attribute("user") - this function will return the user name associated with the login session
response:redirect-to($uri as xs:anyURI) - this function will redirect the user to another URI such as a login panel.
請注意,通常您希望讓使用者能夠輕鬆地返回到他們所在的螢幕。為此,您通常希望在 login.xq XQuery 中新增一個引數,該引數將使用者重定向回他們來自的地方。
response:redirect-to('/exist/rest/db/xrx/apps/user-manager/login.xq?return=/exist/rest/db/myapp/edit/edit.xq?id=47')
以下是一個示例函式,可以放置在所有需要使用者身份驗證的頁面頂部
declare function auth:validate-user() as xs:string {
let $url:= request:get-url()
let $param-names := request:parameter-names()
let $param-string :=for $count in 1 to count($param-names)
let $param := $param-names[$count]
let $value := request:get-parameter($param, '')
let $return := if ($count=1) then (concat('?',$param,'=',$value)) else (concat('&',$param,'=',$value))
return
$return
let $return-param :=fn:string-join($param-string,'')
let $get-session-name :=request:get-session-attribute("user")
let $login-uri := '/exist/rest/db/xrx/apps/user-manager/login.xq?url='
return
if ($get-session-name) then
($get-session-name)
else(
response:redirect-to(xs:anyURI(concat($string,$url,fn:string-join($param-string,'')))))
};