> For the complete documentation index, see [llms.txt](https://zenofchain.gitbook.io/sway-bian-cheng-yu-yan-geng-xin-zhong-the-sway-programming-languageupdatin/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://zenofchain.gitbook.io/sway-bian-cheng-yu-yan-geng-xin-zhong-the-sway-programming-languageupdatin/5.-yong-sway-bu-shu-qu-kuai-lian-blockchain-development-with-sway/5.6-fang-wen-kong-zhi-access-control.md).

# 5.6 访问控制 (Access Control)

Smart contracts require the ability to restrict access to and identify certain users or contracts. Unlike account-based blockchains, transactions in UTXO-based blockchains (i.e. Fuel) do not necessarily have a unique transaction sender. Additional logic is needed to handle this difference, and is provided by the standard library.

智能合约要求能够限制对某些用户或合约的访问及其识别。与基于账户的区块链不同，基于UTXO的区块链（即Fuel）中的交易不一定有一个唯一的交易发送者。需要额外的逻辑来处理这种差异，并由标准库提供。

### `msg_sender`

To deliver an experience akin to the EVM's access control, the `std` library provides a `msg_sender` function, which identifies a unique caller based upon the call and/or transaction input data.

为了提供类似于EVM访问控制的体验，`std`库提供了一个`msg_sender`函数，它根据调用和/或交易输入数据识别一个独特的调用者。

```
contract;

use std::auth::msg_sender;

abi MyOwnedContract {
    fn receive(field_1: u64) -> bool;
}

const OWNER = Address::from(0x9ae5b658754e096e4d681c548daf46354495a437cc61492599e33fc64dcdc30c);

impl MyOwnedContract for Contract {
    fn receive(field_1: u64) -> bool {
        let sender = msg_sender().unwrap();
        if let Identity::Address(addr) = sender {
            assert(addr == OWNER);
        } else {
            revert(0);
        }

        true
    }
}

```

The `msg_sender` function works as follows:\
`msg_sender`函数的工作原理如下：

* If the caller is a contract, then `Result::Ok(Sender)` is returned with the `ContractId` sender variant.\
  如果调用者是一个合约，那么`Result::Ok(Sender)`将被返回，并带有`ContractId`的发送者变量。
* If the caller is external (i.e. from a script), then all coin input owners in the transaction are checked. If all owners are the same, then `Result::Ok(Sender)` is returned with the `Address` sender variant.\
  如果调用者是外部的（即来自脚本），那么将检查交易中所有代币输入的所有者。如果所有所有者都是相同的，那么`Result::Ok(Sender)`将以`Address`发件人变量返回。
* If the caller is external and coin input owners are different, then the caller cannot be determined and a `Result::Err(AuthError)` is returned.\
  如果调用者是外部的，而代币输入所有者是不同的，那么调用者就无法确定，并返回\`Result::Err(AuthError)'。

### 合约所有权 (Contract Ownership)

Many contracts require some form of ownership for access control. To accomplish this, it is recommended that a storage variable of type `Option<Identity>` is used to keep track of the owner. This allows setting and revoking ownership using the variants `Some(..)` and `None` respectively. This is better, safer, and more readable than using the `Identity` type directly where revoking ownership has to be done using some magic value such as `std::constants::ZERO_B256` or otherwise.

许多合约需要某种形式的所有权来进行访问控制。为了达到这个目的，建议使用一个`Option<Identity>`类型的存储变量来跟踪所有者。这允许使用变体`Some(..)`和`None`分别设置和撤销所有权。这比直接使用`Identity`类型更好、更安全、更易读，在那里，撤销所有权必须使用一些“魔法”值，如`std::constants::ZERO_B256`或其他。

The following is an example of how to properly set ownership of a contract:\
下面是一个如何正确设置合约所有权的例子：

```
    #[storage(write)]
    fn set_owner(identity: Identity) {
        storage.owner.write(Option::Some(identity));
    }

```

The following is an example of how to properly revoke ownership of a contract:\
下面是一个如何正确撤销合约所有权的例子：

```
    #[storage(write)]
    fn revoke_ownership() {
        storage.owner.write(Option::None);
    }

```
