springboot+mybatis整合shiro——登陸認證和權限控制

  • 引依賴

shiro-all包含shiro全部的包、shiro-core是核心包、shiro-web是與web整合、shiro-spring是與spring整合、shiro-ehcache是與EHCache整合、shiro-quartz是與任務調度quartz整合等等。java

<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配置

shiroConfiguration.javaweb

@Configuration
public class ShiroConfiguration {
    /**
     * ShiroFilterFactoryBean 處理攔截資源文件問題。
     * 注意:單獨一個ShiroFilterFactoryBean配置是或報錯的,覺得在
     * 初始化ShiroFilterFactoryBean的時候須要注入:SecurityManager
     *
     * Filter Chain定義說明 一、一個URL能夠配置多個Filter,使用逗號分隔 二、當設置多個過濾器時,所有驗證經過,才視爲經過
     * 三、部分過濾器可指定參數,如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;
    }

}

shiroRealm.javaajax

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;
    }
}
相關文章
相關標籤/搜索