zoukankan      html  css  js  c++  java
  • springboot+mybatis+shiro——登录认证和权限控制

    转载:https://z77z.oschina.io/

    一、引入依赖

    shiro-all包含shiro所有的包、shiro-core是核心包、shiro-web是与web整合、shiro-spring是与spring整合、shiro-ehcache是与EHCache整合、shiro-quartz是与任务调度quartz整合等等。

    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-core</artifactId>
        <version>1.2.2</version>
    </dependency>
    
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-web</artifactId>
        <version>1.2.2</version>
    </dependency>
    
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-ehcache</artifactId>
        <version>1.2.2</version>
    </dependency>
    
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-spring</artifactId>
        <version>1.2.2</version>
    </dependency>

    二、导入数据库

    SET FOREIGN_KEY_CHECKS=0;
    
    -- ----------------------------
    -- Table structure for u_permission
    -- ----------------------------
    DROP TABLE IF EXISTS `u_permission`;
    CREATE TABLE `u_permission` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT,
      `url` varchar(256) DEFAULT NULL COMMENT 'url地址',
      `name` varchar(64) DEFAULT NULL COMMENT 'url描述',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of u_permission
    -- ----------------------------
    INSERT INTO `u_permission` VALUES ('1', '/user/select', '用户查询');
    INSERT INTO `u_permission` VALUES ('2', '/admin/add', '管理员添加');
    INSERT INTO `u_permission` VALUES ('3', '/admin/delete', '管理员删除');
    
    -- ----------------------------
    -- Table structure for u_role
    -- ----------------------------
    DROP TABLE IF EXISTS `u_role`;
    CREATE TABLE `u_role` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT,
      `name` varchar(32) DEFAULT NULL COMMENT '角色名称',
      `type` varchar(10) DEFAULT NULL COMMENT '角色类型',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of u_role
    -- ----------------------------
    INSERT INTO `u_role` VALUES ('1', 'admin', '1');
    INSERT INTO `u_role` VALUES ('2', 'user', '1');
    INSERT INTO `u_role` VALUES ('3', 'visitor', '1');
    
    -- ----------------------------
    -- Table structure for u_role_permission
    -- ----------------------------
    DROP TABLE IF EXISTS `u_role_permission`;
    CREATE TABLE `u_role_permission` (
      `rid` bigint(20) DEFAULT NULL COMMENT '角色ID',
      `pid` bigint(20) DEFAULT NULL COMMENT '权限ID'
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of u_role_permission
    -- ----------------------------
    INSERT INTO `u_role_permission` VALUES ('1', '3');
    INSERT INTO `u_role_permission` VALUES ('1', '2');
    INSERT INTO `u_role_permission` VALUES ('2', '1');
    
    -- ----------------------------
    -- Table structure for u_user
    -- ----------------------------
    DROP TABLE IF EXISTS `u_user`;
    CREATE TABLE `u_user` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT,
      `nickname` varchar(20) DEFAULT NULL COMMENT '用户昵称',
      `email` varchar(128) DEFAULT NULL COMMENT '邮箱|登录帐号',
      `pswd` varchar(32) DEFAULT NULL COMMENT '密码',
      `create_time` datetime DEFAULT NULL COMMENT '创建时间',
      `last_login_time` datetime DEFAULT NULL COMMENT '最后登录时间',
      `status` bigint(1) DEFAULT '1' COMMENT '1:有效,0:禁止登录',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of u_user
    -- ----------------------------
    INSERT INTO `u_user` VALUES ('1', 'admin', null, '123456', '2017-05-10 20:22:59', null, '1');
    INSERT INTO `u_user` VALUES ('2', 'user', null, '123456', null, null, '1');
    
    -- ----------------------------
    -- Table structure for u_user_role
    -- ----------------------------
    DROP TABLE IF EXISTS `u_user_role`;
    CREATE TABLE `u_user_role` (
      `uid` bigint(20) DEFAULT NULL COMMENT '用户ID',
      `rid` bigint(20) DEFAULT NULL COMMENT '角色ID'
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of u_user_role
    -- ----------------------------
    INSERT INTO `u_user_role` VALUES ('1', '1');
    INSERT INTO `u_user_role` VALUES ('2', '2');
    SET FOREIGN_KEY_CHECKS=1;

    三、Controller层

    @RestController
    public class AdminController {
        
         private static Logger logger = LoggerFactory.getLogger(AdminController.class);
    
        @Autowired
        private URoleDao uRoleDao;
    
        //跳转到登录表单页面
        @RequestMapping(value = "/login", method = RequestMethod.GET)
        public String login() {
            return "need login";
        }
        
        //登录成功后,跳转的页面
        @RequestMapping("/success")
        public String index(Model model) {
            return "success";
        }
    
        //未登录,可以访问的页面
        @RequestMapping("/index")
        public String list(Model model) {
            return "index";
        }
        
        //登陆验证,这里方便url测试,正式上线需要使用POST方式提交
        @RequestMapping(value = "/ajaxLogin", method = RequestMethod.GET)
        public String index(UUser user) {
            if (user.getNickname() != null && user.getPswd() != null) {
                UsernamePasswordToken token = new UsernamePasswordToken(user.getNickname(), user.getPswd(), "login");
                Subject currentUser = SecurityUtils.getSubject();
                logger.info("对用户[" + user.getNickname() + "]进行登录验证..验证开始");
                try {
                    currentUser.login( token );
                    //验证是否登录成功
                    if (currentUser.isAuthenticated()) {
                        logger.info("用户[" + user.getNickname() + "]登录认证通过(这里可以进行一些认证通过后的一些系统参数初始化操作)");
                        System.out.println("用户[" + user.getNickname() + "]登录认证通过(这里可以进行一些认证通过后的一些系统参数初始化操作)");
                        return "redirect:/";
                    } else {
                        token.clear();
                        System.out.println("用户[" + user.getNickname() + "]登录认证失败,重新登陆");
                        return "redirect:/login";
                    }
                } catch ( UnknownAccountException uae ) {
                    logger.info("对用户[" + user.getNickname() + "]进行登录验证..验证失败-username wasn't in the system");
                } catch ( IncorrectCredentialsException ice ) {
                    logger.info("对用户[" + user.getNickname() + "]进行登录验证..验证失败-password didn't match");
                } catch ( LockedAccountException lae ) {
                    logger.info("对用户[" + user.getNickname() + "]进行登录验证..验证失败-account is locked in the system");
                } catch ( AuthenticationException ae ) {
                    logger.error(ae.getMessage());
                }
            }
            return "login";
        }
          
        /**
         * ajax登录请求接口方式登陆
         * @param username
         * @param password
         * @return
         */
        @RequestMapping(value="/ajaxLogin",method= RequestMethod.POST)
        @ResponseBody
        public Map<String,Object> submitLogin(@RequestParam(value = "nickname") String username, @RequestParam(value = "pswd") String password) {
            Map<String, Object> resultMap = new LinkedHashMap<String, Object>();
            try {
    
                UsernamePasswordToken token = new UsernamePasswordToken(username, password);
                SecurityUtils.getSubject().login(token);
                resultMap.put("status", 200);
                resultMap.put("message", "登录成功");
    
            } catch (Exception e) {
                resultMap.put("status", 500);
                resultMap.put("message", e.getMessage());
            }
            return resultMap;
        }
    
        //登出
        @RequestMapping(value = "/logout")
        public String logout(){
            return "logout";
        }
    
        //错误页面展示
        @GetMapping("/403")
        public String error(){
            return "error ok!";
        }
    
        //管理员功能
        @RequiresRoles("admin")
        @RequiresPermissions("管理员添加")
        @RequestMapping(value = "/admin/add")
        public String create(){
            return "add success!";
        }
    
        //用户功能
        @RequiresRoles("user")
        @RequiresPermissions("用户查询")
        @RequestMapping(value = "/user/select")
        public String detail(){
            return "select success"; 
      }
    }

    四、shiro配置

    1.shiroConfiguration.java

    @Configuration
    public class ShiroConfiguration {
        /**
         * ShiroFilterFactoryBean 处理拦截资源文件问题。
         * 注意:单独一个ShiroFilterFactoryBean配置是或报错的,以为在
         * 初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager
         *
         * Filter Chain定义说明 1、一个URL可以配置多个Filter,使用逗号分隔 2、当设置多个过滤器时,全部验证通过,才视为通过
         * 3、部分过滤器可指定参数,如perms,roles
         *
         */
    
        @Bean(name = "lifecycleBeanPostProcessor")
        public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
            return new LifecycleBeanPostProcessor();
        }
    
        @Bean(name = "shiroRealm")
        @DependsOn("lifecycleBeanPostProcessor")
        public ShiroRealm shiroRealm() {
            ShiroRealm realm = new ShiroRealm();
            return realm;
        }
    
        @Bean(name = "ehCacheManager")
        @DependsOn("lifecycleBeanPostProcessor")
            public EhCacheManager ehCacheManager(){
            EhCacheManager ehCacheManager = new EhCacheManager();
            return ehCacheManager;
        }
    
        @Bean(name = "securityManager")
        public DefaultWebSecurityManager securityManager(){
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            securityManager.setRealm(shiroRealm());
            securityManager.setCacheManager(ehCacheManager());//用户授权/认证信息Cache, 采用EhCache 缓存
            return securityManager;
        }
    
        @Bean(name = "shiroFilter")
        public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager){
            ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
            shiroFilterFactoryBean.setSecurityManager(securityManager);
    
            System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
    
            // 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边
            Map<String, String> filterChainDefinitionManager = new LinkedHashMap<String, String>();
            // 配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了
            filterChainDefinitionManager.put("/logout", "logout");
            // authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问
            filterChainDefinitionManager.put("/user/**", "authc,roles[user]");
            filterChainDefinitionManager.put("/admin/**", "authc,roles[admin]");
            filterChainDefinitionManager.put("/login", "anon");
            filterChainDefinitionManager.put("/index", "anon");
            filterChainDefinitionManager.put("/ajaxLogin", "anon");
            filterChainDefinitionManager.put("/statistic/**",  "anon");
            filterChainDefinitionManager.put("/**",  "authc,roles[user]");//其他资源全部拦截
            shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionManager);
    
            // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
            shiroFilterFactoryBean.setLoginUrl("/login");
            // 登录成功后要跳转的链接
            shiroFilterFactoryBean.setSuccessUrl("/success");
            // 未授权界面
            shiroFilterFactoryBean.setUnauthorizedUrl("/403");
    
            return shiroFilterFactoryBean;
        }
    
        @Bean
        @ConditionalOnMissingBean
        public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
            DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();
            daap.setProxyTargetClass(true);
            return daap;
        }
    
        @Bean
        public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
            AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();
            aasa.setSecurityManager(securityManager);
            return aasa;
        }
    
    }

    2.shiroRealm.java

    public class ShiroRealm extends AuthorizingRealm {
    
        private Logger logger = LoggerFactory.getLogger(ShiroRealm.class);
    
        //一般这里都写的是servic,这里省略直接调用dao
        @Autowired
        private UUserDao uUserDao;
        @Autowired
        private URoleDao uRoleDao;
        @Autowired
        private UPermissionDao uPermissionDao;
    
        /**
         * 登录认证
         * @param authenticationToken
         * @return
         * @throws AuthenticationException
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
            logger.info("验证当前Subject时获取到token为:" + token.toString());
            //查出是否有此用户
            String username = token.getUsername();
            UUser hasUser = uUserDao.selectAllByName(username);
    
            if (hasUser != null) {
                // 若存在,将此用户存放到登录认证info中,无需自己做密码对比,Shiro会为我们进行密码对比校验
                List<URole> rlist = uRoleDao.findRoleByUid(hasUser.getId());//获取用户角色
                List<UPermission> plist = uPermissionDao.findPermissionByUid(hasUser.getId());//获取用户权限
                List<String> roleStrlist=new ArrayList<String>();////用户的角色集合
                List<String> perminsStrlist=new ArrayList<String>();//用户的权限集合
                for (URole role : rlist) {
                    roleStrlist.add(role.getName());
                }
                for (UPermission uPermission : plist) {
                    perminsStrlist.add(uPermission.getName());
                }
                hasUser.setRoleStrlist(roleStrlist);
                hasUser.setPerminsStrlist(perminsStrlist);
             // 若存在,将此用户存放到登录认证info中,无需自己做密码对比,Shiro会为我们进行密码对比校验
                return new SimpleAuthenticationInfo(hasUser, hasUser.getPswd(), getName());
            }
    
            return null;
        }
    
        /**
         * 权限认证
         * @param principalCollection
         * @return
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            logger.info("##################执行Shiro权限认证##################");
            UUser user = (UUser) principalCollection.getPrimaryPrincipal();
            if (user != null) {
                //权限信息对象info,用来存放查出的用户的所有的角色(role)及权限(permission)
                SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
                //用户的角色集合
                info.addRoles(user.getRoleStrlist());
                //用户的权限集合
                info.addStringPermissions(user.getPerminsStrlist());
    
                return info;
            }
            // 返回null的话,就会导致任何用户访问被拦截的请求时,都会自动跳转到unauthorizedUrl指定的地址
            return null;
        }
    }

    五、测试

    1.登录

    2.查询

  • 相关阅读:
    POJ 3468 A Simple Problem with Integers(线段树 区间更新)
    Windows Mobile 6.0 SDK和中文模拟器下载
    Linux学习笔记——例说makefile 头文件查找路径
    uva 11427
    腾讯2014年实习生招聘笔试面试经历
    AVC1与H264的差别
    oracle递归函数
    全部编程皆为Web编程
    JavaScript--语法2--语句结构
    JavaScript--变量和运算符
  • 原文地址:https://www.cnblogs.com/nananana/p/9341056.html
Copyright © 2011-2022 走看看