zoukankan      html  css  js  c++  java
  • SpringBoot整合shiro从初恋到失恋

    建个项目或者模块,目录结构如下

    在pom.xml中加入shiro依赖,其他依赖自行添加(lombok,jpa,mybatis,web,thymeleaf等)

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

    application.properties中的配置

    
    ##端口号
    server.port=8888
    ##数据库配置
    ##数据库地址
    spring.datasource.url=jdbc:mysql://localhost:3306/shiro?characterEncoding=utf8&useSSL=false
      &serverTimezone=GMT%2B8
    ##数据库用户名
    spring.datasource.username=root
    ##数据库密码
    spring.datasource.password=Panbing936@
    ##数据库驱动
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    ##validate  加载hibernate时,验证创建数据库表结构
    ##create   每次加载hibernate,重新创建数据库表结构,这就是导致数据库表数据丢失的原因。
    ##create-drop        加载hibernate时创建,退出是删除表结构
    ##update                 加载hibernate自动更新数据库结构
    ##validate 启动时验证表的结构,不会创建表
    ##none  启动时不做任何操作
    spring.jpa.hibernate.ddl-auto=update
    ##控制台打印sql
    spring.jpa.show-sql=true
    # 建议在开发时关闭缓存,不然没法看到实时页面
    spring.thymeleaf.cache=false
    ##去除thymeleaf的html严格校验
    spring.thymeleaf.mode=LEGACYHTML5
    #没下面这行配置就会报这个错误
    #Caused by: org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment]
    spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
    

    实体类SysMenu.java中的代码

    @Entity
    @Data
    public class SysMenu implements Serializable {
    
        @Id
        @GeneratedValue
        private Integer menuId;
        private String menuName;
    
        @ManyToMany
        @JoinTable(name = "SysRoleMenu", joinColumns = {@JoinColumn(name = "menuId")}, inverseJoinColumns = {@JoinColumn(name = "roleId")})
        private List<SysRole> roleList;
    }
    

    实体类SysRole.java中的代码

    @Entity
    @Data
    public class SysRole implements Serializable {
    
        @Id
        @GeneratedValue
        private Integer roleId;
    
        private String roleName;
    
        //多对多关系
        @ManyToMany(fetch = FetchType.EAGER)
        @JoinTable(name = "SysRoleMenu", joinColumns = {@JoinColumn(name = "roleId")}, inverseJoinColumns = {@JoinColumn(name = "menuId")})
        private List<SysMenu> menuList;
    
        //多对多关系
        @ManyToMany
        @JoinTable(name = "SysUserRole", joinColumns = {@JoinColumn(name = "roleId")}, inverseJoinColumns = {@JoinColumn(name = "userId")})
        private List<SysUser> userList;// 一个角色对应多个用户
    }
    

    实体类SysUser.java中的代码

    @Entity
    @Data
    public class SysUser implements Serializable {
    
        @Id
        @GeneratedValue
        private Integer userId;
        @NotEmpty
        private String userName;
        @NotEmpty
        private String passWord;
    
        //多对多关系
        @ManyToMany(fetch = FetchType.EAGER)
        //急加载,加载一个实体时,定义急加载的属性会立即从数据库中加载
        //FetchType.LAZY:懒加载,加载一个实体时,定义懒加载的属性不会马上从数据库中加载
        @JoinTable(name = "SysUserRole", joinColumns = {@JoinColumn(name = "userId")},
                inverseJoinColumns = {@JoinColumn(name = "roleId")})
        private List<SysRole> roleList;// 一个用户具有多个角色
    
    }
    

    接口UserRepository.java中的代码

    public interface UserRepository extends CrudRepository<SysUser,Long> {
    
        SysUser findByUserName(String username);
    }
    

    下面的代码才是shiro相关的

    MyshiroRealm.java

    public class MyShiroRealm extends AuthorizingRealm {
    
        @Resource
        private UserRepository userRepository;
    
        //授权
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
            SysUser userInfo  = (SysUser)principals.getPrimaryPrincipal();
            for(SysRole role:userInfo.getRoleList()){
                authorizationInfo.addRole(role.getRoleName());
                for(SysMenu menu:role.getMenuList()){
                    authorizationInfo.addStringPermission(menu.getMenuName());
                }
            }
            return authorizationInfo;
        }
    
        //认证
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
                throws AuthenticationException {
            //获得当前用户的用户名
            String username = (String)token.getPrincipal();
            System.out.println(token.getCredentials());
            //根据用户名找到对象
            //实际项目中,这里可以根据实际情况做缓存,如果不做,Shiro自己也是有时间间隔机制,2分钟内不会重复执行该方法
            SysUser userInfo = userRepository.findByUserName(username);
            if(userInfo == null){
                return null;
            }
            //这里会去校验密码是否正确
            SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                    userInfo, //用户名
                    userInfo.getPassWord(),//密码
                    getName()
            );
            return authenticationInfo;
        }
    }
    

    ShiroConfig.java

    @Configuration
    public class ShiroConfig {
        private final Logger logger = LoggerFactory.getLogger(this.getClass());
    
        @Bean
        public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
            logger.info("启动shiroFilter--时间是:" + new Date());
            ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
            shiroFilterFactoryBean.setSecurityManager(securityManager);
            //shiro拦截器
            Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();
            //<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
            //<!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边 -->
    
            // 配置不被拦截的资源及链接
            filterChainDefinitionMap.put("/static/**", "anon");
            // 退出过滤器
            filterChainDefinitionMap.put("/logout", "logout");
    
            //配置需要认证权限的
            filterChainDefinitionMap.put("/**", "authc");
            // 如果不设置默认会自动寻找Web工程根目录下的"/login"页面,即本文使用的login.html
            shiroFilterFactoryBean.setLoginUrl("/login");
            // 登录成功后要跳转的链接
            shiroFilterFactoryBean.setSuccessUrl("/index");
    
            //未授权界面
            shiroFilterFactoryBean.setUnauthorizedUrl("/403");
            shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
            return shiroFilterFactoryBean;
        }
    
        //自定义身份认证Realm(包含用户名密码校验,权限校验等)
        @Bean
        public MyShiroRealm myShiroRealm(){
            MyShiroRealm myShiroRealm = new MyShiroRealm();
            return myShiroRealm;
        }
    
    
        @Bean
        public SecurityManager securityManager(){
            DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
            securityManager.setRealm(myShiroRealm());
            return securityManager;
        }
    
        //开启shiro aop注解支持,不开启的话权限验证就会失效
        @Bean
        public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
            AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
            authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
            return authorizationAttributeSourceAdvisor;
        }
    
        //配置异常处理,不配置的话没有权限后台报错,前台不会跳转到403页面
        @Bean(name="simpleMappingExceptionResolver")
        public SimpleMappingExceptionResolver
        createSimpleMappingExceptionResolver() {
            SimpleMappingExceptionResolver simpleMappingExceptionResolver = new SimpleMappingExceptionResolver();
            Properties mappings = new Properties();
            mappings.setProperty("DatabaseException", "databaseError");//数据库异常处理
            mappings.setProperty("UnauthorizedException","403");
            simpleMappingExceptionResolver.setExceptionMappings(mappings);  // None by default
            simpleMappingExceptionResolver.setDefaultErrorView("error");    // No default
            simpleMappingExceptionResolver.setExceptionAttribute("ex");     // Default is "exception"
            return simpleMappingExceptionResolver;
        }
    }
    

    thymeleaf的页面代码

    index.html

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    index
    <br/>
    <form th:action="@{/logout}" method="post">
        <p><input type="submit" value="重新登录"/></p>
    </form>
    <form th:action="@{/select}" method="get">
        <p><input type="submit" value="查看"/></p>
    </form>
    <form th:action="@{/delete}" method="get">
        <p><input type="submit" value="删除"/></p>
    </form>
    </body>
    </html>
    

    login.html

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
    <head>
        <meta charset="UTF-8">
        <title>Login</title>
    </head>
    <body>
    错误信息:<h4 th:text="${msg}"></h4>
    <form action="" method="post">
        <p>账号:<input type="text" name="username" value="dalaoyang"/></p>
        <p>密码:<input type="text" name="password" value="123"/></p>
        <p><input type="submit" value="登录"/></p>
    </form>
    </body>
    </html>
    

    另外三个跳转页面就不贴出来了,panpan账号登录可以查看和删除,用xiaoli账号登录则只有查看而没有删除的权限,代码见下面,sql文件在resources包下

    github代码

    个人网站

  • 相关阅读:
    python 正则表达式练习题
    python2与Python3的区别
    Python :生成一个1到50的大字符串,每个数字之间有个空格 1 2 3 4 ..........50
    关于实现今天到一年中任意一天两者之间的天数差的计算
    Window下pip的安装
    Pycharm中Git、Github的简单使用和配置
    Python中字符串操作函数string.split('str1')和string.join(ls)
    实现无密码远程登陆另一台机器
    我的第一篇博客
    String类型转List<Integer>
  • 原文地址:https://www.cnblogs.com/panbingwen/p/10828014.html
Copyright © 2011-2022 走看看