Selector de archivos
El Selector de archivos v8 permite usar la misma funcionalidad que se usa en el servicio M365 dentro de las soluciones. Es decir, a medida que iteramos y mejoramos el servicio, esas nuevas funcionalidades aparecen para los usuarios.
Este nuevo "control" es una página hospedada en el servicio de Microsoft con la que usted interactúa a través de mensajes de publicación. La página se puede hospedar incrustada en un iframe o como un elemento emergente.
Puede encontrar la documentación del selector 7.2 aquí.
Configuración necesaria
Para ejecutar los ejemplos o usar el control en la solución, deberá crear una aplicación de AAD. Luego, haga lo siguiente:
- Cree un nuevo registro de aplicación de AAD y anote el identificador de la aplicación.
- En autenticación, cree un nuevo registro de aplicación de página única
- Establezca el identificador URI de redireccionamiento en
https://localhost
(esto es para probar los ejemplos) - Asegúrese de comprobar los tokens de acceso y los tokens de identificador.
- Opcionalmente, puede configurar esta aplicación para varios inquilinos, pero esto no se tratará en el presente artículo
- Establezca el identificador URI de redireccionamiento en
- Agregar permisos de API
- Agregue
Files.Read.All
,Sites.Read.All
, dejeUser.Read
para los permisos delegados de Graph - Agregue
AllSites.Read
,MyFiles.Read
para permisos delegados de SharePoint
- Agregue
Si está desarrollando en SharePoint Framework, puede solicitar estos permisos en el manifiesto de aplicación con el recurso "SharePoint" y "Microsoft Graph".
Para permitir que el usuario cargue archivos y cree carpetas en la experiencia del selector, puede solicitar acceso a
Files.ReadWrite.All
,Sites.ReadWrite.All
,AllSites.Write
yMyFiles.Write
.
Permissions
El selector de archivos siempre funciona con permisos delegados y, como tal, solo puede acceder a archivos y carpetas a los que el usuario actual ya tiene acceso.
Como mínimo, debe solicitar el permiso MyFiles.Read de SharePoint para leer archivos de los sitios de OneDrive y SharePoint de un usuario.
Revise la tabla siguiente para comprender qué permisos son necesarios en función de las operaciones que desea realizar. Todos los permisos de esta tabla hacen referencia a los permisos delegados.
Lectura | Escritura | |
---|---|---|
OneDrive | SharePoint.MyFiles.Read Otra posibilidad: Graph.Files.Read |
SharePoint.MyFiles.Write Otra posibilidad: Graph.Files.ReadWrite |
Sitios de SharePoint | SharePoint.MyFiles.Read Otra posibilidad: Graph.Files.Read Otra posibilidad: SharePoint.AllSites.Read |
SharePoint.MyFiles.Write Otra posibilidad: Graph.Files.ReadWrite Otra posibilidad: SharePoint.AllSites.Write |
Canales de Teams | Graph.ChannelSettings.Read.All y SharePoint.AllSites.Read | Graph.ChannelSettings.Read.All y SharePoint.AllSites.Write |
Cómo funciona
Para usar el control, debe:
- Realice una solicitud POST en la página de "control" hospedada en /_layouts/15/FilePicker.aspx. Con esta solicitud se proporcionan algunos parámetros, el principal es la configuración del selector.
- Configure los mensajes entre la aplicación host y el control mediante postMessage y los puertos de mensaje.
- Una vez establecido el canal de comunicación, debe responder a varios "comandos", el primero de ellos consiste en proporcionar tokens de autenticación.
- Por último, tendrá que responder a mensajes de comando adicionales para proporcionar tokens de autenticación nuevos o diferentes, controlar los archivos elegidos o cerrar el elemento emergente.
En las próximas secciones se explica cada paso.
También tenemos una variedad de ejemplos que muestran diferentes formas de integrarse con el control.
Iniciar el selector
Para iniciar el selector, debe crear una "ventana". que puede ser un iframe o un elemento emergente. Una vez que tenga una ventana, debe construir un formulario y publicar el formulario en la dirección URL {baseUrl}/_layouts/15/FilePicker.aspx
con los parámetros de cadena de consulta definidos.
El valor {baseUrl}
anterior es la dirección URL web de SharePoint de la web de destino o el OneDrive del usuario. Algunos ejemplos son: "https://tenant.sharepoint.com/sites/dev" o "https://tenant-my.sharepoint.com".
Configuración del consumidor de OneDrive
name | Descripciones |
---|---|
autoridad | https://login.microsoftonline.com/consumers |
Ámbito | OneDrive.ReadWrite o OneDrive.ReadOnly |
baseUrl | https://onedrive.live.com/picker |
Cuando solicite un token, usará
OneDrive.ReadOnly
oOneDrive.ReadWrite
cuando solicite el token. Cuando solicite los permisos para la aplicación, seleccionará paraFiles.Read
oFiles.ReadWrite
(u otro ámbito Files.X).
// create a new window. The Picker's recommended maximum size is 1080x680, but it can scale down to
// a minimum size of 250x230 for very small screens or very large zoom.
const win = window.open("", "Picker", "width=1080,height=680");
// we need to get an authentication token to use in the form below (more information in auth section)
const authToken = await getToken({
resource: baseUrl,
command: "authenticate",
type: "SharePoint",
});
// to use an iframe you can use code like:
// const frame = document.getElementById("iframe-id");
// const win = frame.contentWindow;
// now we need to construct our query string
// options: These are the picker configuration, see the schema link for a full explaination of the available options
const queryString = new URLSearchParams({
filePicker: JSON.stringify(options),
locale: 'en-us'
});
// Use MSAL to get a token for your app, specifying the resource as {baseUrl}.
const accessToken = await getToken(baseUrl);
// we create the absolute url by combining the base url, appending the _layouts path, and including the query string
const url = baseUrl + `/_layouts/15/FilePicker.aspx?${queryString}`);
// create a form
const form = win.document.createElement("form");
// set the action of the form to the url defined above
// This will include the query string options for the picker.
form.setAttribute("action", url);
// must be a post request
form.setAttribute("method", "POST");
// Create a hidden input element to send the OAuth token to the Picker.
// This optional when using a popup window but required when using an iframe.
const tokenInput = win.document.createElement("input");
tokenInput.setAttribute("type", "hidden");
tokenInput.setAttribute("name", "access_token");
tokenInput.setAttribute("value", accessToken);
form.appendChild(tokenInput);
// append the form to the body
win.document.body.append(form);
// submit the form, this will load the picker page
form.submit();
Configuración del selector
El selector se configura serializando un objeto JSON que contenga la configuración deseada y anexándole a los valores de cadena de consulta como se muestra en la sección Iniciar el selector. También puede ver el esquema completo. Como mínimo, debe proporcionar la configuración de autenticación, entrada y mensajería.
A continuación se muestra un ejemplo de objeto de configuración mínima. Con esto se configura la mensajería en el canal 27, se permite que el selector sepa que podemos proporcionar tokens y que queremos la pestaña " Mis archivos" para representar los archivos de OneDrive del usuario. Esta configuración usaría una baseUrl del formulario "https://{tenant}-my.sharepoint.com";
const channelId = uuid(); // Always use a unique id for the channel when hosting the picker.
const options = {
sdk: "8.0",
entry: {
oneDrive: {}
},
// Applications must pass this empty `authentication` option in order to obtain details item data
// from the picker, or when embedding the picker in an iframe.
authentication: {},
messaging: {
origin: "http://localhost:3000",
channelId: channelId
},
}
El selector está diseñado para funcionar tanto con OneDrive como con SharePoint en una instancia determinada y solo se debe incluir una de las secciones de entrada.
Localización
La interfaz del selector de archivos admite la localización del mismo conjunto de idiomas que SharePoint.
Para establecer el idioma del selector de archivos, use el parámetro de cadena de consulta locale
establecido en uno de los valores LCID de la lista anterior.
Establecer mensajería
Una vez creada la ventana y el formulario enviado, deberá establecer un canal de mensajería. Se usa para recibir los comandos del selector y responder.
let port: MessagePort;
function initializeMessageListener(event: MessageEvent): void {
// we validate the message is for us, win here is the same variable as above
if (event.source && event.source === win) {
const message = event.data;
// the channelId is part of the configuration options, but we could have multiple pickers so that is supported via channels
// On initial load and if it ever refreshes in its window, the Picker will send an 'initialize' message.
// Communication with the picker should subsequently take place using a `MessageChannel`.
if (message.type === "initialize" && message.channelId === options.messaging.channelId) {
// grab the port from the event
port = event.ports[0];
// add an event listener to the port (example implementation is in the next section)
port.addEventListener("message", channelMessageListener);
// start ("open") the port
port.start();
// tell the picker to activate
port.postMessage({
type: "activate",
});
}
}
};
// this adds a listener to the current (host) window, which the popup or embed will message when ready
window.addEventListener("message", messageEvent);
Implementación del agente de escucha de mensajes
La solución debe controlar varios mensajes del selector, clasificados como notificaciones o comandos. Las notificaciones no esperan respuesta y se pueden considerar información de registro. La única excepción es la notificación page-loaded
resaltada a continuación, que le indicará que el selector está listo.
Los comandos requieren su confirmación y, en función del comando, una respuesta. En esta sección se muestra una implementación de ejemplo de la función channelMessageListener
agregada como agente de escucha de eventos al puerto. En las secciones siguientes se habla en detalle sobre las notificaciones y los comandos.
async function channelMessageListener(message: MessageEvent): Promise<void> {
const payload = message.data;
switch (payload.type) {
case "notification":
const notification = payload.data;
if (notification.notification === "page-loaded") {
// here we know that the picker page is loaded and ready for user interaction
}
console.log(message.data);
break;
case "command":
// all commands must be acknowledged
port.postMessage({
type: "acknowledge",
id: message.data.id,
});
// this is the actual command specific data from the message
const command = payload.data;
// command.command is the string name of the command
switch (command.command) {
case "authenticate":
// the first command to handle is authenticate. This command will be issued any time the picker requires a token
// 'getToken' represents a method that can take a command and return a valid auth token for the requested resource
try {
const token = await getToken(command);
if (!token) {
throw new Error("Unable to obtain a token.");
}
// we report a result for the authentication via the previously established port
port.postMessage({
type: "result",
id: message.data.id,
data: {
result: "token",
token: token,
}
});
} catch (error) {
port.postMessage({
type: "result",
id: message.data.id,
data: {
result: "error",
error: {
code: "unableToObtainToken",
message: error.message
}
}
});
}
break;
case "close":
// in the base of popup this is triggered by a user request to close the window
await close(command);
break;
case "pick":
try {
await pick(command);
// let the picker know that the pick command was handled (required)
port.postMessage({
type: "result",
id: message.data.id,
data: {
result: "success"
}
});
} catch (error) {
port.postMessage({
type: "result",
id: message.data.id,
data: {
result: "error",
error: {
code: "unusableItem",
message: error.message
}
}
});
}
break;
default:
// Always send a reply, if if that reply is that the command is not supported.
port.postMessage({
type: "result",
id: message.data.id,
data: {
result: "error",
error: {
code: "unsupportedCommand",
message: command.command
}
}
});
break;
}
break;
}
}
Obtener token
El control requiere que podamos proporcionarle tokens de autenticación en función del comando enviado. Para ello, creamos un método que toma un comando y devuelve un token como se muestra a continuación. Estamos usando el @azure/msal-browser
paquete para controlar el trabajo de autenticación.
Actualmente, el control se basa en tokens de SharePoint y no en Graph, por lo que deberá asegurarse de que el recurso es correcto y no puede reutilizar tokens para llamadas de Graph.
import { PublicClientApplication, Configuration, SilentRequest } from "@azure/msal-browser";
import { combine } from "@pnp/core";
import { IAuthenticateCommand } from "./types";
const app = new PublicClientApplication(msalParams);
async function getToken(command: IAuthenticateCommand): Promise<string> {
let accessToken = "";
const authParams = { scopes: [`${combine(command.resource, ".default")}`] };
try {
// see if we have already the idtoken saved
const resp = await app.acquireTokenSilent(authParams!);
accessToken = resp.accessToken;
} catch (e) {
// per examples we fall back to popup
const resp = await app.loginPopup(authParams!);
app.setActiveAccount(resp.account);
if (resp.idToken) {
const resp2 = await app.acquireTokenSilent(authParams!);
accessToken = resp2.accessToken;
} else {
// throw the error that brought us here
throw e;
}
}
return accessToken;
}
Resultados de elementos seleccionados
Cuando se selecciona un elemento, el selector devolverá, a través del canal de mensajería, una matriz de elementos seleccionados. Aunque hay un conjunto de información que se puede devolver, siempre se garantiza que se incluye lo siguiente:
{
"id": string,
"parentReference": {
"driveId": string
},
"@sharePoint.endpoint": string
}
Con esto puede construir una dirección URL para realizar una solicitud GET para obtener cualquier información que necesite sobre el archivo seleccionado. Por lo general, tendría el siguiente formato:
@sharePoint.endpoint + /drives/ + parentReference.driveId + /items/ + id
Tendrá que incluir un token válido con los derechos adecuados para leer el archivo en la solicitud.
Carga de archivos
Si concede Files.ReadWrite.All
permisos a la aplicación que usa para los tokens de selector, aparecerá un widget en el menú superior que le permitirá cargar archivos y carpetas en la biblioteca de documentos de OneDrive o SharePoint. No se requieren otros cambios de configuración, este comportamiento se controla mediante los permisos de aplicación y usuario. Tenga en cuenta que si el usuario no tiene acceso a la ubicación para cargar, el selector no mostrará la opción.
Guía de personalización de marca
Las aplicaciones que se integran con el selector de archivos de Microsoft OneDrive también pueden optar por promover su integración con OneDrive a los clientes. Dado que OneDrive tiene una oferta comercial y de consumidor, las siguientes opciones están disponibles para mostrarse en interfaces de aplicación de terceros:
- Microsoft OneDrive (personal)
- También se puede mostrar como Microsoft OneDrive para personal
- Microsoft OneDrive (profesional o educativo)
- También se puede mostrar como Microsoft OneDrive para el trabajo o la escuela