亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

 更新時(shí)間:2019年03月09日 16:05:12   作者:喵先生的進(jìn)階之路  
這篇文章主要介紹了Spring實(shí)現(xiàn)擁有者權(quán)限驗(yàn)證的方法示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

問(wèn)題描述

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

實(shí)體關(guān)系

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

實(shí)現(xiàn)思路

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

利用切面,我們可以在findById、update、delete方法上進(jìn)行驗(yàn)證。

注解

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

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

因?yàn)槲覀冃枰@取出學(xué)生,但是并不限于學(xué)生,所以就要將倉(cāng)庫(kù)repository作為一個(gè)參數(shù)傳入。

實(shí)體

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

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

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

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

教師:

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

班級(jí):

@Entity
public 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é)生:

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

切面

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

@Aspect
@Component
public class OwnerAuthorityAspect {
  private static final Logger logger = LoggerFactory.getLogger(OwnerAuthorityAspect.class.getName());

  /**
   * 使用注解,并第一個(gè)參數(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) {
  }

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

這里我們利用applicationContext來(lái)獲取倉(cāng)庫(kù)bean,然后再利用獲取到的bean,生成repository對(duì)象。

@Aspect
@Component
public class OwnerAuthorityAspect implements ApplicationContextAware {
  private ApplicationContext applicationContext = null;  // 初始化上下文
  ......
  @Before("doAccessCheck(id, authorityAnnotation)")
  public void before(Long id, AuthorityAnnotation authorityAnnotation) {
    logger.debug("獲取注解上的repository, 并通過(guò)applicationContext來(lái)獲取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;
  }
}

該類(lèi)實(shí)現(xiàn)了ApplicationContextAware接口,通過(guò)setApplicationContext函數(shù)獲取到了applicationContext。

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

@Before("doAccessCheck(id, authorityAnnotation)")
public void before(Long id, AuthorityAnnotation authorityAnnotation) {
  logger.debug("獲取注解上的repository, 并通過(guò)applicationContext來(lái)獲取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("獲取實(shí)體對(duì)象");
  Optional<BaseEntity> baseEntityOptional = crudRepository.findById(id);
  if(!baseEntityOptional.isPresent()) {
    throw new RuntimeException("對(duì)不起,未找到相關(guān)的記錄");
  }
  BaseEntity baseEntity = baseEntityOptional.get();

  logger.debug("獲取登錄用戶以及擁有者,并進(jìn)行比對(duì)");
  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;
  }

  /**
   * 通過(guò)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)的問(wèn)題

實(shí)現(xiàn)之后,進(jìn)行單元測(cè)試的過(guò)程中出現(xiàn)了問(wèn)題。

@Test
public void update() throws Exception {
  logger.info("獲取一個(gè)保存學(xué)生");
  Student student = studentService.getOneSaveStudent();
  Long id = student.getId();
  logger.info("獲取一個(gè)更新學(xué)生");
  Student newStudent = studentService.getOneUnSaveStudent();

  String jsonString = JSONObject.toJSONString(newStudent);
  logger.info("發(fā)送更新請(qǐng)求");
  this.mockMvc
    .perform(put(baseUrl + "/" + id)
      .cookie(this.cookie)
      .content(jsonString)
      .contentType(MediaType.APPLICATION_JSON_UTF8))
    .andExpect(status().isOk());
}

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

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

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

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

解決

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

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

  }
}

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

總結(jié)

 以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java接口DAO模式代碼原理及應(yīng)用詳解

    Java接口DAO模式代碼原理及應(yīng)用詳解

    這篇文章主要介紹了Java接口DAO模式代碼原理及應(yīng)用詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-11-11
  • 詳解SpringBoot如何實(shí)現(xiàn)緩存預(yù)熱

    詳解SpringBoot如何實(shí)現(xiàn)緩存預(yù)熱

    緩存預(yù)熱是指在 Spring Boot 項(xiàng)目啟動(dòng)時(shí),預(yù)先將數(shù)據(jù)加載到緩存系統(tǒng)(如 Redis)中的一種機(jī)制,下面我們就來(lái)看看SpringBoot是如何實(shí)現(xiàn)緩存預(yù)熱的吧
    2024-01-01
  • JAVA設(shè)計(jì)模式之解釋器模式詳解

    JAVA設(shè)計(jì)模式之解釋器模式詳解

    這篇文章主要介紹了JAVA設(shè)計(jì)模式之解釋器模式詳解,解釋器模式是類(lèi)的行為模式,給定一個(gè)語(yǔ)言之后,解釋器模式可以定義出其文法的一種表示,并同時(shí)提供一個(gè)解釋器,需要的朋友可以參考下
    2015-04-04
  • 如何使用ByteArrayOutputStream下載文件

    如何使用ByteArrayOutputStream下載文件

    這篇文章主要介紹了如何使用ByteArrayOutputStream下載文件方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • java學(xué)習(xí)指南之字符串與正則表達(dá)式

    java學(xué)習(xí)指南之字符串與正則表達(dá)式

    在日常Java后端開(kāi)發(fā)過(guò)程中,免不了對(duì)數(shù)據(jù)字段的解析,自然就少不了對(duì)字符串的操作,這其中就包含了正則表達(dá)式這一塊的內(nèi)容,下面這篇文章主要給大家介紹了關(guān)于java學(xué)習(xí)指南之字符串與正則表達(dá)式的相關(guān)資料,需要的朋友可以參考下
    2023-05-05
  • Java線程創(chuàng)建靜態(tài)代理模式代碼實(shí)例

    Java線程創(chuàng)建靜態(tài)代理模式代碼實(shí)例

    這篇文章主要介紹了Java線程創(chuàng)建靜態(tài)代理模式代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-11-11
  • java?-jar/-cp啟動(dòng)添加外部的依賴包方式

    java?-jar/-cp啟動(dòng)添加外部的依賴包方式

    這篇文章主要介紹了java?-jar/-cp啟動(dòng)添加外部的依賴包方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • 解決spring boot創(chuàng)建項(xiàng)目遇到配置的問(wèn)題

    解決spring boot創(chuàng)建項(xiàng)目遇到配置的問(wèn)題

    這篇文章主要介紹了解決spring boot創(chuàng)建項(xiàng)目遇到配置的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • SPRING管理XML方式過(guò)程解析

    SPRING管理XML方式過(guò)程解析

    這篇文章主要介紹了SPRING管理XML方式過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10
  • Java安全框架——Shiro的使用詳解(附springboot整合Shiro的demo)

    Java安全框架——Shiro的使用詳解(附springboot整合Shiro的demo)

    這篇文章主要介紹了Java安全框架——Shiro的使用詳解,幫助大家更好的理解和學(xué)習(xí)使用Shiro,感興趣的朋友可以了解下
    2021-04-04

最新評(píng)論