springboot项目整合shiro实现简单的权限验证

引言

本文主要实现springboot项目整合shiro实现简单的权限验证,包括用户登录认证,不同的角色访问受权限管控的接口,不同权限的用户访问受不同权限管控的接口等操作,数据库表包含user(用户表)、role(角色表)、perm(权限表)、user_role_relation(用户角色对应关系表)、role_perm_relation(角色权限对应关系表)。其中用户可以有多个角色,单个角色也可以有多个权限。

一、引入依赖

yaml 复制代码
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.7.1</version>
        </dependency>

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>1.5.3</version>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.23</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.4.3</version>
        </dependency>

二、自定义realm

java 复制代码
public class myRealm extends AuthorizingRealm {

    @Autowired
    private RoleService roleService;
    @Autowired
    private PermsService permsService;
    @Autowired
    private UserService userService;

    // 实现对用户的授权功能,通过用户登录的信息查找到用户所有的角色以及角色对应的权限集合,并将用户的角色以及权限集合设置到AuthorizationInfo对象中返回,
    // 可以用于后续接口(Controller)中通过 @RequiresRoles("admin") 注解限制特定角色访问该接口,@RequiresPermissions("perm:delete") 注解限制有指定权限的用户访问接口
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        Subject subject = SecurityUtils.getSubject();
        User principal = (User)subject.getPrincipal();
        Set<String> roleSet = roleService.getRoleNameByUserId(principal.getId());
        Set<String> permSet = permsService.getPermByUserId(principal.getId());
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setRoles(roleSet);
        info.setStringPermissions(permSet);

        return info;
    }


    // 实现对用户登录认证的功能,也就是实现subject.login(usernamePasswordToken)对应的功能,这里的参数authenticationToken和usernamePasswordToken相对应
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;

        User user = userService.lambdaQuery().eq(User::getUsername,token.getUsername()).one();
        if(user!=null){
            return new SimpleAuthenticationInfo(user,user.getPassword(),getName());
        }
        return null;
    }
}

三、创建shiro配置类

java 复制代码
@Configuration
public class ShiroConfig {

    // 将自定义的myRealm实现类交由spring容器管理,并设置加密规则
    @Bean
    public myRealm getRealm(){
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        matcher.setHashAlgorithmName("md5");
        matcher.setHashIterations(1024);
        myRealm realm = new myRealm();
        realm.setCredentialsMatcher(matcher);
        return realm;
    }

    // spring自动将容器中的myRealm类型的bean注入到对应参数中,无需通过 @Qualifier指定
    @Bean
    public DefaultWebSecurityManager getSecurityManager(myRealm realm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(realm);
        return securityManager;
    }

    // 可以在这里设置过滤规则
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        return shiroFilterFactoryBean;
    }



    /**
     * 以下两个bean是开启注解方式控制访问url
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
        defaultAAP.setProxyTargetClass(true);
        return defaultAAP;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }


}

四、接口的编写

UserController控制器

java 复制代码
@RestController
public class UserController {
    @Autowired
    private UserService userService;
    @Autowired
    private UserRoleRelationService userRoleRelationService;

    @PostMapping("/register")
    public R register(@RequestBody User user){
        Md5Hash md5Hash = new Md5Hash(user.getPassword(),null,1024);
        user.setPassword(md5Hash.toHex());
        if(userService.save(user)){
            userRoleRelationService.batchInsert(user.getId(),user.getRoleIdList());
            return R.ok().message("用户注册成功");
        }else {
            return R.error().message("用户注册失败");
        }
    }

    @PostMapping("/login")
    public R login(@RequestBody User user){
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(user.getUsername(),user.getPassword());

        try{

            subject.login(usernamePasswordToken);
            User u = (User)subject.getPrincipal();
            subject.getSession().setAttribute("user",u);


        }catch (UnknownAccountException e){
            return R.error().message("用户名错误");
        }catch (IncorrectCredentialsException e){
            return R.error().message("密码错误");
        }
        return R.ok().message("登录成功");
    }

    @GetMapping("/logout")
    public R logout(){
        Subject subject = SecurityUtils.getSubject();
        User currentUser = (User) subject.getPrincipal();
        subject.logout();
        return R.ok().message("当前用户"+currentUser.getUsername()+"退出登录");
    }

    @GetMapping("/getCurrentUser")
    public R getCurrentUser(){
        Subject subject = SecurityUtils.getSubject();
        User principal = (User)subject.getPrincipal();
        return R.ok().data("currentUser",principal);
    }

}

PermController控制器

java 复制代码
@RestController
public class PermController {
    @Autowired
    private PermsService permsService;

    @PostMapping("/addPerm")
    @RequiresRoles("admin")
    public R addPerm(@RequestBody Perms perms){
        if(permsService.save(perms)){
            return R.ok().message("新增权限成功");
        }else {
            return R.error().message("新增权限失败");
        }
    }

    @GetMapping("/deletePerm")
    @RequiresPermissions("perm:delete")
    public R deletePerm(Integer id){
        if(permsService.removeById(id)){
            return R.ok().message("删除成功");
        }else {
            return R.error().message("删除失败");
        }
    }

    @PostMapping("/empower")
    @RequiresRoles("admin")
    public R empower(@RequestBody Perms perms){
        if(permsService.batchInsert(perms)){
            return R.ok().message("对当前角色授权成功");
        }else {
            return R.error().message("授权出现异常");
        }
    }
}
相关推荐
virus59451 小时前
悟空CRM mybatis-3.5.3-mapper.dtd错误解决方案
java·开发语言·mybatis
计算机毕设VX:Fegn08952 小时前
计算机毕业设计|基于springboot + vue蛋糕店管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
没差c2 小时前
springboot集成flyway
java·spring boot·后端
三水不滴3 小时前
Redis 过期删除与内存淘汰机制
数据库·经验分享·redis·笔记·后端·缓存
时艰.3 小时前
Java 并发编程之 CAS 与 Atomic 原子操作类
java·开发语言
编程彩机3 小时前
互联网大厂Java面试:从Java SE到大数据场景的技术深度解析
java·大数据·spring boot·面试·spark·java se·互联网大厂
笨蛋不要掉眼泪3 小时前
Spring Boot集成LangChain4j:与大模型对话的极速入门
java·人工智能·后端·spring·langchain
Yvonne爱编码3 小时前
JAVA数据结构 DAY3-List接口
java·开发语言·windows·python
像少年啦飞驰点、4 小时前
零基础入门 Spring Boot:从“Hello World”到可上线微服务的完整学习指南
java·spring boot·微服务·编程入门·后端开发
眼眸流转5 小时前
Java代码变更影响分析(一)
java·开发语言