国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發(fā) > Java > 正文

Spring實現(xiàn)擁有者權(quán)限驗證的方法示例

2024-07-14 08:43:53
字體:
供稿:網(wǎng)友

問題描述

在做權(quán)限驗證的時候,我們經(jīng)常會遇到這樣的情況:教師擁有多個學(xué)生,但是在處理學(xué)生信息的時候,教師只能操作自己班級的學(xué)生。所以,我們要做的就是,當(dāng)教師嘗試處理別的班的學(xué)生的時候,拋出異常。

實體關(guān)系

用戶1:1教師,教師m:n班級,班級1:n學(xué)生

Spring,擁有者,權(quán)限驗證

實現(xiàn)思路

findById為例。因為從整體上看,用戶學(xué)生m:n的關(guān)系,所以在調(diào)用這個接口的時候,獲取該學(xué)生的所有用戶,然后跟當(dāng)前登錄用戶進(jìn)行對比,如果不在其中,拋出異常。

利用切面,我們可以在findByIdupdatedelete方法上進(jìn)行驗證。

注解

我們會在方法上添加注解,以表示對該方法進(jìn)行權(quán)限驗證。

@Target(ElementType.METHOD)     // 注解使用在方法上@Retention(RetentionPolicy.RUNTIME) // 運(yùn)行時生效public @interface AuthorityAnnotation {  /**   * 倉庫名   */  @Required  Class repository();}

因為我們需要獲取出學(xué)生,但是并不限于學(xué)生,所以就要將倉庫repository作為一個參數(shù)傳入。

實體

上面我們說過,需要獲取學(xué)生中的用戶,所以我們可以在實體中定義一個方法,獲取所有有權(quán)限的用戶:getBelongUsers()

但是,我們知道,學(xué)生和用戶沒用直接的關(guān)系,而且為了復(fù)用,在對其他實體進(jìn)行驗證的時候也能使用,可以考慮創(chuàng)建一個接口,讓需要驗證的實體去實現(xiàn)他。

Spring,擁有者,權(quán)限驗證

這樣,我們可以在讓每個實體都集成這個接口,然后形成鏈?zhǔn)秸{(diào)用,這樣就解決了上面你的兩個問題。

public interface BaseEntity {  List<User> getBelongToUsers();}

教師:

@Entitypublic class Teacher implements YunzhiEntity, BaseEntity {  ...  @Override  public List<User> getBelongToUsers() {    List<User> userList = new ArrayList<>();    userList.add(this.getUser());    return userList;  }}

班級:

@Entitypublic class Klass implements BaseEntity {  ...  @Override  public List<User> getBelongToUsers() {    List<User> userList = new ArrayList<>();    for (Teacher teacher: this.getTeacherList()) {      userList.addAll(teacher.getBelongToUsers());    }    return userList;  }}

學(xué)生:

@Entitypublic class Student implements BaseEntity {  ...  @Override  public List<User> getBelongToUsers() {    return this.getKlass().getBelongToUsers();  }}

切面

有了實體后,我們就可以建立切面實現(xiàn)驗證功能了。

@Aspect@Componentpublic class OwnerAuthorityAspect {  private static final Logger logger = LoggerFactory.getLogger(OwnerAuthorityAspect.class.getName());  /**   * 使用注解,并第一個參數(shù)為id   */  @Pointcut("@annotation(com.yunzhiclub.alice.annotation.AuthorityAnnotation) && args(id,..) && @annotation(authorityAnnotation)")  public void doAccessCheck(Long id, AuthorityAnnotation authorityAnnotation) {   }    @Before("doAccessCheck(id, authorityAnnotation)")  public void before(Long id, AuthorityAnnotation authorityAnnotation) {  }

首先,我們要獲取到待操作對象。但是在獲取對象之前,我們必須獲取到repository

這里我們利用applicationContext來獲取倉庫bean,然后再利用獲取到的bean,生成repository對象。

@Aspect@Componentpublic class OwnerAuthorityAspect implements ApplicationContextAware {  private ApplicationContext applicationContext = null;  // 初始化上下文  ......  @Before("doAccessCheck(id, authorityAnnotation)")  public void before(Long id, AuthorityAnnotation authorityAnnotation) {    logger.debug("獲取注解上的repository, 并通過applicationContext來獲取bean");    Class<?> repositoryClass = authorityAnnotation.repository();    Object object = applicationContext.getBean(repositoryClass);    logger.debug("將Bean轉(zhuǎn)換為CrudRepository");    CrudRepository<BaseEntity, Object> crudRepository = (CrudRepository<BaseEntity, Object>)object;  }  @Override  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {    this.applicationContext = applicationContext;  }}

該類實現(xiàn)了ApplicationContextAware接口,通過setApplicationContext函數(shù)獲取到了applicationContext

接下來,就是利用repository獲取對象,然后獲取他的所屬用戶,再與當(dāng)前登錄用戶進(jìn)行比較。

@Before("doAccessCheck(id, authorityAnnotation)")public void before(Long id, AuthorityAnnotation authorityAnnotation) {  logger.debug("獲取注解上的repository, 并通過applicationContext來獲取bean");  Class<?> repositoryClass = authorityAnnotation.repository();  Object object = applicationContext.getBean(repositoryClass);  logger.debug("將Bean轉(zhuǎn)換為CrudRepository");  CrudRepository<BaseEntity, Object> crudRepository = (CrudRepository<BaseEntity, Object>)object;  logger.debug("獲取實體對象");  Optional<BaseEntity> baseEntityOptional = crudRepository.findById(id);  if(!baseEntityOptional.isPresent()) {    throw new RuntimeException("對不起,未找到相關(guān)的記錄");  }  BaseEntity baseEntity = baseEntityOptional.get();  logger.debug("獲取登錄用戶以及擁有者,并進(jìn)行比對");  List<User> belongToTUsers = baseEntity.getBelongToUsers();  User currentLoginUser = userService.getCurrentLoginUser();  Boolean havePermission = false;  if (currentLoginUser != null && belongToTUsers.size() != 0) {    for (User user: belongToTUsers) {      if (user.getId().equals(currentLoginUser.getId())) {        havePermission = true;        break;      }  }    if (!havePermission) {      throw new RuntimeException("權(quán)限不允許");    }  }}

使用

在控制器的方法上使用注解:@AuthorityAnnotation,傳入repository。

@RestController@RequestMapping("/student")public class StudentController {  private final StudentService studentService;  // 學(xué)生  @Autowired  public StudentController(StudentService studentService) {    this.studentService = studentService;  }  /**   * 通過id獲取學(xué)生   *   * @param id   * @return   */  @AuthorityAnnotation(repository = StudentRepository.class)  @GetMapping("/{id}")  @JsonView(StudentJsonView.get.class)  public Student findById(@PathVariable Long id) {    return studentService.findById(id);  }}

出現(xiàn)的問題

實現(xiàn)之后,進(jìn)行單元測試的過程中出現(xiàn)了問題。

@Testpublic void update() throws Exception {  logger.info("獲取一個保存學(xué)生");  Student student = studentService.getOneSaveStudent();  Long id = student.getId();  logger.info("獲取一個更新學(xué)生");  Student newStudent = studentService.getOneUnSaveStudent();  String jsonString = JSONObject.toJSONString(newStudent);  logger.info("發(fā)送更新請求");  this.mockMvc    .perform(put(baseUrl + "/" + id)      .cookie(this.cookie)      .content(jsonString)      .contentType(MediaType.APPLICATION_JSON_UTF8))    .andExpect(status().isOk());}

Spring,擁有者,權(quán)限驗證

400的錯誤,說明參數(shù)錯誤,參數(shù)傳的是實體,看下傳了什么:

Spring,擁有者,權(quán)限驗證

我們看到,這個字段并不是我們實體中的字段,但是為什么序列化的時候出現(xiàn)了這個字段呢?

原因是這樣的,我們在實體中定義了一個getBelongToUsers函數(shù),然后JSONobject在進(jìn)行序列化的時候會根據(jù)實體中的getter方法,獲取get后面的為key,也就是將belongToUsers看做了字段。

所以就出現(xiàn)了上面?zhèn)鲗嶓w字段多出的情況,從而引發(fā)了400的錯誤。

解決

我們不想JSONobject在序列化的時候處理getBelongToUsers,就需要聲明一下,這里用到了注解:@JsonIgnore。這樣在序列化的時候就會忽略它。

@Entitypublic class Student implements BaseEntity {  ......  @JsonIgnore  @Override  public List<User> getBelongToUsers() {    return this.getKlass().getBelongToUsers();  }}

修改后的學(xué)生實體如上,其他實現(xiàn)了getBelongToUsers方法的,都需要做相同處理。

總結(jié)

 以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持VeVb武林網(wǎng)。


注:相關(guān)教程知識閱讀請移步到JAVA教程頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 新野县| 西乌珠穆沁旗| 金乡县| 望都县| 绿春县| 云阳县| 日喀则市| 罗源县| 绿春县| 商都县| 内黄县| 衡东县| 南郑县| 得荣县| 鹿邑县| 安吉县| 海安县| 盐亭县| 增城市| 郑州市| 米易县| 汶上县| 万全县| 九江县| 苍溪县| 白沙| 巴马| 太原市| 长葛市| 汤阴县| 楚雄市| 千阳县| 宜阳县| 乡宁县| 松原市| 青神县| 盱眙县| 曲阳县| 城固县| 林甸县| 安泽县|