• SpringBoot整合Shiro+mybatis-plus



    源码地址: link

    一、添加依赖

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.joecy</groupId>
        <artifactId>springboot_mybatis-plus_shiro</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <packaging>jar</packaging>
    
        <name>springboot_mybatis-plus_shiro</name>
        <description>Spring Boot整合Mybitis Plus和Shiro小Demo</description>
    
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>1.5.9.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <properties>
            <java.version>1.8</java.version>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
            <mybatisplus-spring-boot-starter.version>1.0.5</mybatisplus-spring-boot-starter.version>
            <mybatisplus.version>2.1.4</mybatisplus.version>
            <shiro-spring.version>1.3.2</shiro-spring.version>
            <druid.version>1.0.18</druid.version>
            <lombok.version>1.18.2</lombok.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <!--没有此依赖shiro注解权限会失效-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-aop</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-logging</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-freemarker</artifactId>
            </dependency>
            <!--lombok插件使用依赖-->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
                <scope>provided</scope>
            </dependency>
            <!--mybatis plus依赖-->
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatisplus-spring-boot-starter</artifactId>
                <version>${mybatisplus-spring-boot-starter.version}</version>
            </dependency>
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus</artifactId>
                <version>${mybatisplus.version}</version>
            </dependency>
            <!--数据源相关-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <scope>runtime</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>${druid.version}</version>
            </dependency>
            <!--shiro依赖-->
            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-spring</artifactId>
                <version>${shiro-spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
    
            <!--热部署-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
                <scope>runtime</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>springloaded</artifactId>
            </dependency>
        </dependencies>
    </project>
    

    二、application.properties配置文件

    server.port=8080
    # 数据库访问配置
    # 主数据源,默认的
    spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus_shiro_test?Unicode=true&characterEncoding=utf-8
    spring.datasource.username=root
    spring.datasource.password=123456
    
    # 下面为连接池的补充设置,应用到上面所有数据源中
    # 初始化大小,最小,最大
    spring.datasource.initialSize=5
    spring.datasource.minIdle=5
    spring.datasource.maxActive=20
    # 配置获取连接等待超时的时间
    spring.datasource.maxWait=60000
    # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
    spring.datasource.timeBetweenEvictionRunsMillis=60000
    # 配置一个连接在池中最小生存的时间,单位是毫秒
    spring.datasource.minEvictableIdleTimeMillis=300000
    spring.datasource.validationQuery=SELECT 1 FROM DUAL
    spring.datasource.testWhileIdle=true
    spring.datasource.testOnBorrow=false
    spring.datasource.testOnReturn=false
    # 打开PSCache,并且指定每个连接上PSCache的大小
    spring.datasource.poolPreparedStatements=true
    spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
    # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
    spring.datasource.filters=stat,wall,log4j
    # 通过connectProperties属性来打开mergeSql功能;慢SQL记录
    spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
    # 合并多个DruidDataSource的监控数据
    #spring.datasource.useGlobalDataSourceStat=true
    
    #集成Freemark
    spring.freemarker.cache=false
    spring.freemarker.charset=UTF-8
    spring.freemarker.check-template-location=true
    spring.freemarker.content-type=text/html
    spring.freemarker.expose-request-attributes=true
    spring.freemarker.expose-session-attributes=true
    spring.freemarker.request-context-attribute=request
    spring.freemarker.allow-session-override=true
    #Mybatis配置
    mybatis-plus.mapper-locations=classpath:mappers/*.xml
    #mybatis-plus的model包
    mybatis-plus.typeAliasesPackage=com.joecy.entity
    #global-config:
    #主键类型  0:"数据库ID自增", 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID";
    #id-type: 2
    mybatis-plus.global-config.id-type=0
    #驼峰式命名映射
    mybatis-plus.global-config.db-column-underline=true
    

    三、mybatis-plus相关

    1 新建数据库表对应的model,以SecUser为例

    /**
     * 用户表
     * 需要继承mybatis-plus的Model<>抽象类
     */
    @Data
    public class SecUser extends Model<SecUser> {
    
        //指定id
        @TableId
        private Integer id;
        private String username;
        private String password;
        @TableField(exist = false)
        private List<SecRole> roles;
    
        //实现默认id方法
        //若一个表没有id 直接return null即可
        @Override
        protected Serializable pkVal() {
            return this.id;
        }
    }
    

    2 创建SecUser对应Mapper SecUserMapper

    //必须添加mybatis的@Mapper注解
    @Mapper
    public interface SecUserMapper extends BaseMapper<SecUser> {
    }
    

    至此该model就可以正常使用了,具体使用方法很简单,参照mybatis-plus官网:link

    四、现在开始Shiro配置

    1 创建MyShiroRealm

    //实现AuthorizingRealm接口用户用户认证
    public class MyShiroRealm extends AuthorizingRealm {
    
        //角色权限和对应权限添加
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            //添加角色和权限
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
            System.out.println(principalCollection.getPrimaryPrincipal());
            SecUser user= (SecUser) principalCollection.getPrimaryPrincipal();
            //保存所有角色名
            Set<String> allRoles = new HashSet<>();
            //保存所有权限名
            Set<String> allPermissions = new HashSet<>();
            //查询对应角色
            List<SecUserRole> secUserRoles = new SecUserRole().selectList(new EntityWrapper().eq("user_id", user.getId()));
            for (SecUserRole userRole:secUserRoles) {
                SecRole role = new SecRole();
                role.setId(userRole.getRoleId());
                role = role.selectById();
                allRoles.add(role.getName());
    
                //查询所有权限
                List<SecPermission> permissions = new ArrayList<>();
                List<SecRolePermission> rolePermissions = new SecRolePermission().selectList(new EntityWrapper().eq("role_id", role.getId()));
                for (SecRolePermission rolePermission:rolePermissions) {
                    SecPermission permission = new SecPermission();
                    permission.setId(rolePermission.getPermissionId());
                    permission = permission.selectById();
                    allPermissions.add(permission.getName());
                }
            }
            //添加角色
            simpleAuthorizationInfo.addRoles(allRoles);
            simpleAuthorizationInfo.addStringPermissions(allPermissions);
    
    
            System.out.println(user);
    
            return simpleAuthorizationInfo;
        }
    
        //用户认证
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            // 1、登录认证的方法需要先执行,需要用他来判断登录的用户信息是否合法
            String username = (String) token.getPrincipal();    // 取得用户名
            // 需要通过用户名取得用户的完整信息,利用业务层操作
            SecUser user = null;
            try {
                user = new SecUser().selectOne(new EntityWrapper().eq("username",username));
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (user == null) {
                throw new UnknownAccountException("该用户名称不存在!");
            } else {    // 进行密码的验证处理
                String password =new String((char[]) token.getCredentials());
                // 将数据库中的密码与输入的密码进行比较,这样就可以确定当前用户是否可以正常登录
                if (user.getPassword().equals(password)) {    // 密码正确
    
                    AuthenticationInfo auth = new SimpleAuthenticationInfo(user, password, "memberRealm");
                    return auth;
                } else {
                    throw new IncorrectCredentialsException("密码错误!");
                }
            }
        }
    }
    

    2 创建Shiro配置类ShiroConfig

    @Configuration
    public class ShiroConfig {
    
        //将自己的验证方式加入容器
        @Bean
        public MyShiroRealm myShiroRealm() {
            MyShiroRealm myShiroRealm = new MyShiroRealm();
            return myShiroRealm;
        }
    
        //权限管理,配置主要是Realm的管理认证
        @Bean
        public SecurityManager securityManager() {
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            securityManager.setRealm(myShiroRealm());
            return securityManager;
        }
    
        //Filter工厂,设置对应的过滤条件和跳转条件
        @Bean
        public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
            ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
    
            // 必须设置 SecurityManager
            shiroFilterFactoryBean.setSecurityManager(securityManager);
    
            // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
            shiroFilterFactoryBean.setLoginUrl("/login");
            // 登录成功后要跳转的链接
            shiroFilterFactoryBean.setSuccessUrl("/index");
    
    
            // 权限控制map.
            LinkedHashMap<String, String> filterChainDefinitionMap=new LinkedHashMap<>();
            filterChainDefinitionMap.put("/css/**", "anon"); //表示可以匿名访问
            filterChainDefinitionMap.put("/js/**", "anon"); //表示可以匿名访问
            filterChainDefinitionMap.put("/img/**", "anon"); //表示可以匿名访问
            filterChainDefinitionMap.put("/font/**", "anon"); //表示可以匿名访问
            filterChainDefinitionMap.put("/images/**", "anon"); //表示可以匿名访问
            filterChainDefinitionMap.put("/login", "anon"); //表示可以匿名访问
            filterChainDefinitionMap.put("/user_login", "anon");
            filterChainDefinitionMap.put("/logout*","logout");
            filterChainDefinitionMap.put("/error","anon");
            filterChainDefinitionMap.put("/**","authc");
            shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
            return shiroFilterFactoryBean;
        }
    
        //加入注解的使用,不加入这个注解不生效
        @Bean
        public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
            System.out.println("开启了shiro注解功能");
            AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
            authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
            return authorizationAttributeSourceAdvisor;
        }
    }
    

    3 创建Shiro权限不足处理类ExceptionConf

    /**
     * @author 陈玉林
     * 该类配置Shiro未授权跳转
     */
    @Configuration
    public class ExceptionConf {
        @Bean
        public SimpleMappingExceptionResolver resolver() {
            SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
            Properties properties = new Properties();
            properties.setProperty("org.apache.shiro.authz.UnauthorizedException", "/403");
            resolver.setExceptionMappings(properties);
            return resolver;
        }
    
    }
    

    五、创建LoginController

    @Controller
    public class LoginController {
        @GetMapping(value = "/login")
        public String login(){
            return "login";
        }
    
        @PostMapping(value = "/user_login")
        public String login(@RequestParam String username, @RequestParam String password, Model model){
            try {
                model.addAttribute("username", username);
                UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password);
                Subject subject = SecurityUtils.getSubject();
                //完成登录
                subject.login(usernamePasswordToken);
                return "redirect:/index";
            } catch (Exception e) {
                String ex = e.getClass().getName();
                if (ex != null) {
                    if (UnknownAccountException.class.getName().equals(ex)) {
                        System.out.println("用户名不存在");
                    } else if (IncorrectCredentialsException.class.getName().equals(ex)) {
                        System.out.println("账户或密码错误");
                    } else {
                        System.out.println("未知错误");
                    }
                }
                //返回登录页面
                return "login";
            }
        }
    
        @ResponseBody
        @GetMapping(value = "/index")
        public String index(){
            return "welcome";
        }
    
    
        @RequestMapping("/logout")
        public String logOut(HttpSession session) {
            Subject subject = SecurityUtils.getSubject();
            subject.logout();
            return "redirect:/login";
        }
    
    
    
        //未授权mapping配置
        @ResponseBody
        @GetMapping(value = "/403")
        public String error(){
            return "没有权限!";
        }
    
    
        //注解的使用
        //管理员角色
        @ResponseBody
        @RequiresRoles("admin")
        @RequestMapping(value = "/role/admin")
        public String roleAdmin(){
            return "I am admin";
        }
    
        //普通用户角色
        @ResponseBody
        @RequiresRoles("common")
        @RequestMapping(value = "/role/common")
        public String roleCommon(){
            return "I am common";
        }
    
        //拥有添加、删除权限
        @ResponseBody
        @RequiresPermissions({"add","delete"})
        @RequestMapping(value = "/permissions")
        public String Permissions(){
            return "I have permissions add and delete";
        }
    
        //只拥有添加权限
        @ResponseBody
        @RequiresPermissions("add")
        @RequestMapping(value = "/permission/add")
        public String Permission(){
            return "I have permission add";
        }
    
    }
    

    六、创建一个登录界面

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>login</title>
    </head>
    <body>
    <form action="/user_login" method="post">
        <input type="text" name="username" placeholder="用户名"  >
        <input type="password" name="password" placeholder="密码"  >
        <input type="submit" value="提交">
    </form>
    </body>
    </html>
    

    七、创建数据库,导入doc目录下的sql文件

    数据库结构图

    只有把命运掌握在自己手中,从今天起开始努力,即使暂时看不到希望,也要相信自己。因为比你牛几倍的人,依然在努力。
  • 相关阅读:
    java NIO ;mvn
    查询mysql当前连接数
    lifecycle of opensource products--x86-64
    docker squid---but git proxy should specify by git config --global http.proxy http:...
    java jmx
    zabbix basic concept
    智能手机,医疗诊断,云会议(gotomeeting/citrix)
    子网划分
    Cloudstack4.2之改变数据卷容量的大小(Resize Data Volumes)
    OCFS2 Fencing
  • 原文地址:https://www.cnblogs.com/freesky168/p/14358234.html
Copyright © 2020-2023  润新知