自学内容网 自学内容网

25.01.15 SpringSecurity 授权

//准备工作 在登录通过username查询用户时,把用户对应的角色即角色对应的菜单查出,
//根据用户的角色role  rid来查询对应的菜单
public interface AdminMenuDao extends BaseMapper<AdminMenu> {

    @Select("SELECT m.* FROM admin_menu m ,rel_role_menu rel WHERE m.mid = rel.mid AND rel.rid = #{id}")
    List<AdminMenu> selectListByRid(Long id);
}
@Service("adminMenuService")
public class AdminMenuServiceImpl extends ServiceImpl<AdminMenuDao, AdminMenu> implements AdminMenuService {

    @Resource
    AdminMenuDao adminMenuDao;

    @Override
    public List<AdminMenu> listByRid(Long roleId) {
        List<AdminMenu> allMenuList = adminMenuDao.selectListByRid(roleId);
        List<AdminMenu> firstList = allMenuList.stream()
                .filter(Objects::nonNull)
            //过滤pid不是0的
                .filter(AdminMenu::checkFirst)
                .collect(Collectors.toList());
        //筛选出子菜单
        firstList.forEach(firstMenu ->{
            List<AdminMenu> childList = allMenuList.stream()
                    .filter(Objects::nonNull)
                //级联等比
                    .filter(menu -> firstMenu.getMid().equals(menu.getPid()))
                    .collect(Collectors.toList());
            firstMenu.setChildList(childList);
        });
        

        return firstList;
    }
}
//对上面lam的详细写法
List<AdminMenu> firstList = allMneus.stream()
                .filter(Objects::nonNull)
                .filter(new Predicate<AdminMenu>() {
                    @Override
                    public boolean test(AdminMenu adminMenu) {
                        return adminMenu.checkFirst();
                    }
                }).collect(Collectors.toList());
        firstList.forEach(firstMenu->{
            List<AdminMenu> childList = allMneus.stream()
                    .filter(Objects::nonNull)
                    .filter(new Predicate<AdminMenu>() {
                        @Override
                        public boolean test(AdminMenu adminMenu) {
                            return adminMenu.getPid().equals(adminMenu.getMid());
                        }
                    }).collect(Collectors.toList());
            firstMenu.setChildMenu(childList);
        });

角色信息存入UserDetails

LoginUserDetails(用于拿到数据库信息的类)

 @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        //权限列表,暂时不考虑,所有的连接都没有权限
        //从数据库,已经查询出 角色信息 和菜单信息 到adminUser
        //角色授权,权限标识授权
        //new 返回的 权限列表
        List<GrantedAuthority> authorityList = new ArrayList<>();
        //查询出 角色的信息
        AdminRole adminRole = adminUser.getAdminRole();
        if (adminRole != null){
            SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_" + adminRole.getCode());
            authorityList.add(authority);
        }
       
        return authorityList;
    }

角色授权

                //配置类
                http.authorizeRequests()
                //地址/test1/f1只有角色super_admin可以访问,其他没有提到的地址,是没有设置权限的,只要认证成功,都可以访问
                ///test1/**
                .antMatchers("/test1/f1").hasRole("super_admin")
                .antMatchers("/test1/f2").hasRole("admin")
              .antMatchers("/test1/f3","/test1/f4").hasAnyRole("super_admin","admin")

                .antMatchers("/loginuser/**","/web/**").permitAll()
                .anyRequest().authenticated();

角色继承

    //配置类当中
    @Bean
    public RoleHierarchy roleHierarchy(){
        RoleHierarchyImpl hierarchy = new RoleHierarchyImpl();
        //super_admin权限,大于 admin
        hierarchy.setHierarchy("ROLE_super_admin > ROLE_admin");
        return hierarchy;
    }

权限标识授权

http.authorizeRequests()
                //↑角色授权 ↓权限标识授权
                .antMatchers("/test1/f5").hasAuthority("admin")
                .antMatchers("/test1/f6").hasAuthority("test")
                .antMatchers("/test1/f7").hasAnyAuthority("admin","test")

                .antMatchers("/loginuser/**","/web/**").permitAll()
                .anyRequest().authenticated();

自定义403

http.exceptionHandling().accessDeniedHandler((request,response,e)->createJSON(response,"无权限"));
//报错时显示

注解

开启注解权限的使用

修改 SecurityConfig类

@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)

@Secured

角色继承失效了

    //角色继承失效了
    @Secured({"ROLE_super_admin"})
    @GetMapping("/f1")
    public R f1(){
        return R.ok("f1方法,只有super_admin可以访问");
    }
    @Secured("ROLE_admin")
    @GetMapping("/f2")
    public R f2(){
        return R.ok("f2方法,只有admin可以访问");
    }
    //多个参数时要加{}
    @Secured({"ROLE_super_admin","ROLE_admin"})
    @GetMapping("/f3")
    public R f3(){
        return R.ok("f3方法,只有admin,super_admin可以访问");
    }

@PreAuthorize

方法执行之前,生效的权限

不符合要求不会进入到方法中

控制当前的请求,能不能进入到方法里

    //PreAuthorize角色继承生效了
    @PreAuthorize("hasRole('ROLE_super_admin')")
    @GetMapping("/f1")
    public R f1(){
        return R.ok("f1方法,只有super_admin可以访问");
    }
    @PreAuthorize("hasRole('ROLE_admin')")
    @GetMapping("/f2")
    public R f2(){
        return R.ok("f2方法,只有admin可以访问");
    }
    @PreAuthorize("hasAnyRole('ROLE_super_admin','ROLE_admin')")
    @GetMapping("/f3")
    public R f3(){
        return R.ok("f3方法,只有admin,super_admin可以访问");
    }
    @PreAuthorize("hasAuthority('admin')")
    @GetMapping("/f5")
    public R f5(){
        return R.ok("f5方法,只有admin标识可以访问");
    }
    @PreAuthorize("hasAuthority('test')")
    @GetMapping("/f6")
    public R f6(){
        return R.ok("f6方法,只有test标识可以访问");
    }
    @PreAuthorize("hasAnyAuthority('admin','test')")
    @GetMapping("/f7")
    public R f7(){
        return R.ok("f7方法,只有admin,test标识可以访问");
    }

@PostAuthorize

方法执行之后,返回之前生效

这个请求,可以进入到方法内部,不论是否拦截,都会执行方法

使用方式,和@PreAuthorize一样,只是生效的时机不一样

@PreFilter

对参数 进行过滤,参数类型必须是集合

    //不是拦截是否允许访问,是过滤参数
    @PreFilter("filterObject.roleId > 1 ")
    @GetMapping("/f9")
    public R f9(@RequestBody List<AdminUser> list){
        return R.ok(list);
    }

@PostFilter

对返回结果进行过滤,返回值必须是集合(不能有包装)

    @Resource
    AdminUserService adminUserService;
    @PostFilter("filterObject.roleId > 1")
    @GetMapping("/f10")
    public List<AdminUser> f10(){
        List<AdminUser> list = adminUserService.list();
        return list;
    }
//UserDetails的实现类的这个方法,可以用来存放权限
public Collection<? extends GrantedAuthority> getAuthorities(){}

自定义权限认证方法1通过官方api,获取权限列表,判断是否存在

@Component
public class JavasmExpressAuthorize {
    public boolean f1(String code){
        //code 用户的权限标识,如何判断 用户是否拥有这个权限标识
        //获取当前登录的用户信息
        Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if (principal!=null){
            LoginUserDetails loginUserDetails = (LoginUserDetails) principal;
            //获取 权限列表
            Collection<? extends GrantedAuthority> authorities =
                    loginUserDetails.getAuthorities();
            //判断 里面 是否包含字符串 code
            return authorities.stream().anyMatch(grantedAuthority -> grantedAuthority.getAuthority().equals(code));
        }
        return false;
    }
}
    //@bean对象.方法名,传入参数,
    //如果返回true,允许访问当前方法
    //如果返回false,不允许访问,没有权限
    @PreAuthorize("@javasmExpressAuthorize.f1('admin')")
    @GetMapping("/f11")
    public R f11(){
        System.out.println("=======================================f111");
        return R.ok("f11111");
    }

2,不使用官方的权限列表,自己去做判断,是否可以访问

@Component
public class JavasmPreAuthorize {

    public boolean check(String code) {
        //获取登录用户信息
        Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if (principal != null) {
            LoginUserDetails userDetails = (LoginUserDetails) principal;
            //用户自己的 用户信息
            AdminUser adminUser = userDetails.getAdminUser();
            //获取权限列表
            List<AdminAuthority> authorityList = adminUser.getAuthorityList();
            //把 权限列表中,所有的code 都集合到一起
            if (authorityList != null && authorityList.size() > 0){
                //List<code>
                List<String> codeList = authorityList.stream().map(AdminAuthority::getCode).collect(Collectors.toList());
                //是否包含字符串
                return codeList.contains(code);
            }

        }
        return false;
    }
}
    @PreAuthorize("@javasmPreAuthorize.check('admin')")
    @GetMapping("/f12")
    public R f12(){
        System.out.println("=======================================f12222");
        return R.ok("f12222");
    }

3.根据菜单,认证授权

    @PreAuthorize("@javasmMenuAuthorize.check('/room/info')")
    @GetMapping("/f13")
    public R f13(){
        return R.ok("f13");
    }

@Component
public class JavasmMenuAuthorize {

    public boolean check(String url){
        //获取 用户信息
        Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if (principal != null){
            LoginUserDetails loginUserDetails = (LoginUserDetails) principal;
            return loginUserDetails.checkMenu(url);
        }
        return false;
    }
}
    public boolean checkMenu(String url) {
        if (adminUser!=null){
            //获取 菜单信息
            AdminRole adminRole = adminUser.getAdminRole();
            if (adminRole != null){
                //菜单列表,但是 菜单列表 是父子关系,现在需要把childList 也拿出来
                List<AdminMenu> menuList = adminRole.getMenuList();
                //menuList→stream→获取childList的流→url流
                Stream<String> childMenuUrlList = menuList.stream()
                    //获取该用户的子菜单数据
                        .map(AdminMenu::getChildList)
                    //将上面获取到的自菜单列表转换成一个一个的流,在合并为一个单一的流
                        .flatMap(Collection::stream)
                    //获取菜单URL
                        .map(AdminMenu::getUrl);
                //一级菜单url
                Stream<String> firstMenuUrlList = menuList.stream().map(AdminMenu::getUrl);
                //两个流合并到一起,重新组装
                List<String> urlList = Stream.concat(childMenuUrlList, firstMenuUrlList)
                        .collect(Collectors.toList());
                return urlList.contains(url);
            }
        }

        return false;
    }

//flastMap的完整写法
.flatMap(new Function<List<AdminMenu>, Stream<AdminMenu>>() {
                        @Override
                        public Stream<AdminMenu> apply(List<AdminMenu> adminMenus) {
                            return  adminMenus.stream();
                        }
                    })

原文地址:https://blog.csdn.net/2401_87910368/article/details/145168482

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!