使用C#访问Google Classroom作业AddOnAttachment时遇权限错误
Google Classroom AddOnAttachment操作权限不足问题
以教师账号调用Google Classroom API时,课程、作业(CourseWork)、公告(Announcement)的访问/创建均正常,但AddOnAttachment的列表查询、创建操作全部抛出权限不足错误:
The service classroom has thrown an exception. HttpStatusCode is Forbidden. Request had insufficient authentication scopes.
错误触发位置:
- 查询AddOnAttachment列表时:
foreach (AddOnAttachment item in ccarlr.Execute().AddOnAttachments) - 创建AddOnAttachment时:
cwaoa.Execute()
现有权限配置
当前代码中配置的OAuth2权限范围如下:
static string[] Scopes = { ClassroomService.Scope.ClassroomCourses, ClassroomService.Scope.ClassroomCourseworkmaterials, ClassroomService.Scope.ClassroomCourseworkMe, ClassroomService.Scope.ClassroomCourseworkStudents, ClassroomService.Scope.ClassroomCourseworkStudentsReadonly, ClassroomService.Scope.ClassroomGuardianlinksStudents, ClassroomService.Scope.ClassroomAnnouncements, ClassroomService.Scope.ClassroomCourseworkMe, ClassroomService.Scope.ClassroomProfileEmails, ClassroomService.Scope.ClassroomProfilePhotos, ClassroomService.Scope.ClassroomPushNotifications, ClassroomService.Scope.ClassroomRosters, ClassroomService.Scope.ClassroomStudentSubmissionsMeReadonly, ClassroomService.Scope.ClassroomStudentSubmissionsStudentsReadonly, ClassroomService.Scope.ClassroomTopics };
相关代码示例
完整Classroom类代码
public class Classroom { static string[] Scopes = { ClassroomService.Scope.ClassroomCourses, ClassroomService.Scope.ClassroomCourseworkmaterials, ClassroomService.Scope.ClassroomCourseworkMe, ClassroomService.Scope.ClassroomCourseworkStudents, ClassroomService.Scope.ClassroomCourseworkStudentsReadonly, ClassroomService.Scope.ClassroomGuardianlinksStudents, ClassroomService.Scope.ClassroomAnnouncements, ClassroomService.Scope.ClassroomCourseworkMe, ClassroomService.Scope.ClassroomProfileEmails, ClassroomService.Scope.ClassroomProfilePhotos, ClassroomService.Scope.ClassroomPushNotifications, ClassroomService.Scope.ClassroomRosters, ClassroomService.Scope.ClassroomStudentSubmissionsMeReadonly, ClassroomService.Scope.ClassroomStudentSubmissionsStudentsReadonly, ClassroomService.Scope.ClassroomTopics}; static string ApplicationName = "ControlGoogleMCV"; public GDrive_baj GDrive_bajD = new GDrive_baj(); public void Main() { ClientSecrets secrets = new ClientSecrets() { ClientId = "________________", ClientSecret = "__________________________" }; UserCredential credential; using (var stream = new FileStream(Form1.ObtenerAtributo("rutalocaljson"), FileMode.Open, FileAccess.Read)) { string credPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal); credPath = Path.Combine(credPath, ".credentials/", System.Reflection.Assembly.GetExecutingAssembly().GetName().FullName, "paraclassroom"); credential = Google.Apis.Auth.OAuth2.GoogleWebAuthorizationBroker.AuthorizeAsync(secrets, Scopes, "_________", CancellationToken.None, new FileDataStore(credPath, true)).Result; Console.WriteLine("Credential file saved to: " + credPath); } // Create Classroom API service. var service = new ClassroomService(new BaseClientService.Initializer() { HttpClientInitializer = credential, ApplicationName = ApplicationName, }); // Define request parameters. CoursesResource.ListRequest request = service.Courses.List(); request.PageSize = 10; try { CoursesResource.ListRequest lr = new CoursesResource.ListRequest(service); string cadbusname = Interaction.InputBox("Cadena de búsqueda en el atributo ''name'' del curso. ''Cancelar'' no " + "dará resultado; ''Aceptar'' inicia la búsqueda", "Cadena de búsqueda en el nombre del curso", "Transcripción de la música flamenca 2024/2025" ); if (cadbusname.Length > 0) { foreach (Course c in lr.Execute().Courses) { if (c.Name.Contains(cadbusname)) { string cadbusnametarea = Interaction.InputBox("Cadena de búsqueda en el atributo ''name'' de la tarea. ''Cancelar''" + "no dará resultado; ''Aceptar'' inicia la búsqueda", "Cadena de búsqueda en el nombre de la tarea", "Ejercicio 8."); CoursesResource.CourseWorkResource.ListRequest cwrlr = new CoursesResource.CourseWorkResource.ListRequest(service, c.Id); foreach (CourseWork cwr in cwrlr.Execute().CourseWork) { if (cwr.Title.Contains(cadbusnametarea)) { string idCur = cwr.Id; var cwrmat = cwr.Materials; foreach (var item in cwrmat) { if (item.DriveFile != null) { string tx = "El archivo se ha subido desde Google Drive. El thumbonailurl es : " + item.DriveFile.DriveFile.ThumbnailUrl + ". El enlace alternativo es: " + item.DriveFile.DriveFile.AlternateLink + ". El título es: " + item.DriveFile.DriveFile.Title; } if (item.Link != null) { string tx = "Se trata de un enlace. La url es " + item.Link.Url + ". El thumbonailurl es : " + item.Link.ThumbnailUrl + ". El título es: " + item.Link.Title; } } CoursesResource.CourseWorkResource.AddOnAttachmentsResource.ListRequest ccarlr = new CourseWorkResource.AddOnAttachmentsResource.ListRequest(service, c.Id, idCur); foreach (AddOnAttachment item in ccarlr.Execute().AddOnAttachments) { string nn = item.ItemId; } } } } } }; } catch (Exception e) { string ff = e.Message; } } }
可正常执行的公告创建代码
// 公告可正常创建 Google.Apis.Classroom.v1.Data.Announcement anu = new Announcement(); anu.Text = "El cuerpo del anuncio para el curso Prueba"; Google.Apis.Classroom.v1.CoursesResource.AnnouncementsResource.CreateRequest cr = new CoursesResource.AnnouncementsResource.CreateRequest(service, anu, c.Id); cr.Execute();
失败的AddOnAttachment创建代码
// 权限不足 Google.Apis.Classroom.v1.Data.AddOnAttachment addo = new AddOnAttachment(); addo.Title = "El título del add-on attachment para la tarea Prueba1"; Google.Apis.Classroom.v1.CoursesResource.CourseWorkResource.AddOnAttachmentsResource.CreateRequest cwaoa = new CourseWorkResource.AddOnAttachmentsResource.CreateRequest(service, addo, c.Id, idCur); cwaoa.Execute(); // 此处触发错误
创建CourseWork后立即创建AddOnAttachment仍失败
// CourseWork可正常创建,但创建其AddOnAttachment时仍触发权限错误 Google.Apis.Classroom.v1.Data.CourseWork cw = new CourseWork(); cw.Title = "New courseWork for the course"; cw.WorkType = "Assignment"; cw.State = "PUBLISHED"; String idCW = ""; Google.Apis.Classroom.v1.CoursesResource.CourseWorkResource.CreateRequest cwre = new CourseWorkResource.CreateRequest (service, cw, c.Id); cwre.Execute(); foreach (Google.Apis.Classroom.v1.Data.CourseWork item in cwrlr.Execute().CourseWork) { if (item.Title == cw.Title) { idCW = item.Id; break; } } Google.Apis.Classroom.v1.Data.AddOnAttachment addoA = new AddOnAttachment(); addoA.Title = "The title of the add-on attachment for the task created"; Google.Apis.Classroom.v1.CoursesResource.CourseWorkResource.AddOnAttachmentsResource.CreateRequest cwaoa = new CourseWorkResource.AddOnAttachmentsResource.CreateRequest(service, addoA, c.Id, idCW); cwaoa.Execute(); // 此处触发错误
解决方案
核心原因
当前配置的OAuth2权限范围中,缺少AddOnAttachment操作的专用权限,这类权限和普通CourseWork权限是分离的。
需要添加的权限
针对教师账号,需添加:
ClassroomService.Scope.ClassroomAddOnAttachmentsTeacher:支持教师账号创建、读取、修改AddOnAttachment
操作步骤
- 更新权限范围数组:修改Scopes变量,添加上述权限
static string[] Scopes = { // 保留原有所有权限 ClassroomService.Scope.ClassroomAddOnAttachmentsTeacher // 新增此权限 }; - 删除本地凭据文件:找到代码中
credPath指定的路径(通常是用户目录/.credentials/xxx/paraclassroom),删除该目录下的所有文件。旧凭据的权限范围不包含新增权限,必须重新授权。 - 重新运行代码:此时会触发OAuth授权流程,重新获取包含新权限的凭据。
内容的提问来源于stack exchange,提问作者Manuel Cera Vera
相关产品推荐
相关产品推荐

