springboot-shrio-mybatis登录验证与权限控制
来源:互联网 发布:刘备汉昭烈帝皮肤优化 编辑:程序博客网 时间:2024/05/18 06:25
springboot-shrio-mybatis
一、背景
最近做的一个spingboot项目中用到权限控制,网上也看了其他springboot集成shiro进行权限控制的文档。大多文档用户与角色为多对多关系,角色与权限多对多,我的项目需求用户与角色为单对单,角色与权限多对多。所以自己重新整理了表结构完成。
二、表结构
/*Navicat MySQL Data TransferSource Server : 本地Source Server Version : 50528Source Host : localhost:3306Source Database : shiroTarget Server Type : MYSQLTarget Server Version : 50528File Encoding : 65001Date: 2017-09-14 16:41:39*/SET FOREIGN_KEY_CHECKS=0;-- ------------------------------ Table structure for `sys_permission`-- ----------------------------DROP TABLE IF EXISTS `sys_permission`;CREATE TABLE `sys_permission` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `url` varchar(256) DEFAULT NULL COMMENT 'url地址', `permission` varchar(64) DEFAULT NULL COMMENT '权限初始化', `name` varchar(64) DEFAULT NULL COMMENT '描述', PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;-- ------------------------------ Records of sys_permission-- ----------------------------INSERT INTO `sys_permission` VALUES ('1', '/static/**', 'anon', '静态资源');INSERT INTO `sys_permission` VALUES ('2', '/ajaxLogin', 'anon', 'ajax登录');INSERT INTO `sys_permission` VALUES ('3', '/logout', 'logout', '安全退出');INSERT INTO `sys_permission` VALUES ('4', '/*/*/upload', 'anon', '上传文件');INSERT INTO `sys_permission` VALUES ('5', '/admin/content', 'admin:content', '首页/系统管理');INSERT INTO `sys_permission` VALUES ('6', '/cms/content', 'cms:content', '内容管理');INSERT INTO `sys_permission` VALUES ('7', '/apps/content', 'apps:content', '首页');INSERT INTO `sys_permission` VALUES ('8', '/**', 'authc', '其他全部拦截');INSERT INTO `sys_permission` VALUES ('9', '/cms/article/add', 'article:add', '文章添加');-- ------------------------------ Table structure for `sys_role`-- ----------------------------DROP TABLE IF EXISTS `sys_role`;CREATE TABLE `sys_role` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `name` varchar(32) DEFAULT NULL COMMENT '角色名称', `create_by` varchar(64) DEFAULT NULL COMMENT '创建人', `create_date` datetime DEFAULT NULL COMMENT '创建时间', `update_by` varchar(64) DEFAULT NULL COMMENT '更新者', `update_date` datetime DEFAULT NULL COMMENT '更新时间', PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;-- ------------------------------ Records of sys_role-- ----------------------------INSERT INTO `sys_role` VALUES ('1', 'admin', '1', null, null, null);-- ------------------------------ Table structure for `sys_role_permission`-- ----------------------------DROP TABLE IF EXISTS `sys_role_permission`;CREATE TABLE `sys_role_permission` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `rid` bigint(20) DEFAULT NULL COMMENT '角色ID', `pid` bigint(20) DEFAULT NULL COMMENT '权限ID', PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;-- ------------------------------ Records of sys_role_permission-- ----------------------------INSERT INTO `sys_role_permission` VALUES ('1', '1', '1');INSERT INTO `sys_role_permission` VALUES ('2', '1', '2');INSERT INTO `sys_role_permission` VALUES ('3', '1', '3');INSERT INTO `sys_role_permission` VALUES ('4', '1', '4');INSERT INTO `sys_role_permission` VALUES ('5', '1', '5');INSERT INTO `sys_role_permission` VALUES ('6', '1', '6');INSERT INTO `sys_role_permission` VALUES ('7', '1', '7');INSERT INTO `sys_role_permission` VALUES ('8', '1', '8');-- ------------------------------ Table structure for `sys_user`-- ----------------------------DROP TABLE IF EXISTS `sys_user`;CREATE TABLE `sys_user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号', `no` varchar(100) DEFAULT NULL COMMENT '工号', `password` varchar(100) DEFAULT NULL COMMENT '密码', `name` varchar(100) DEFAULT NULL COMMENT '姓名', `rid` bigint(20) DEFAULT NULL COMMENT '角色id', `rname` varchar(100) DEFAULT NULL COMMENT '角色名称', `email` varchar(200) DEFAULT NULL COMMENT '邮箱', `mobile` varchar(200) DEFAULT NULL COMMENT '手机', `login_ip` varchar(100) DEFAULT NULL COMMENT '当前登录ip', `login_date` datetime DEFAULT NULL COMMENT '当前登录时间', `last_login_ip` varchar(100) DEFAULT NULL COMMENT '最后登陆IP', `last_login_date` datetime DEFAULT NULL COMMENT '最后登陆时间', `create_by` varchar(64) DEFAULT NULL COMMENT '创建者', `create_date` datetime DEFAULT NULL COMMENT '创建时间', `update_by` varchar(64) DEFAULT NULL COMMENT '更新者', `update_date` datetime DEFAULT NULL COMMENT '更新时间', `status` bigint(1) DEFAULT '1' COMMENT '状态(1有效/0禁止登录)', PRIMARY KEY (`id`), KEY `sys_user_update_date` (`update_date`)) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8 COMMENT='用户表';-- ------------------------------ Records of sys_user-- ----------------------------INSERT INTO `sys_user` VALUES ('27', 'admin', '21232f297a57a5a743894a0e4a801fc3', 'admin', '1', 'admin', '11@11.com', '13111111111', null, null, '0:0:0:0:0:0:0:1', '2017-03-08 20:22:31', '2,超级管理员', '2015-11-06 14:01:01', '27,shen', '2017-03-08 20:22:31', '0');
<!-- shiro相关 --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.2.5</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>1.2.5</version> </dependency>
四、shiro配置文件
ShiroConfiguration.java
package com.jdy.conf;import org.apache.shiro.authc.credential.HashedCredentialsMatcher;import org.apache.shiro.cache.ehcache.EhCacheManager;import org.apache.shiro.spring.LifecycleBeanPostProcessor;import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;import org.apache.shiro.spring.web.ShiroFilterFactoryBean;import org.apache.shiro.web.mgt.DefaultWebSecurityManager;import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.DependsOn;import java.util.LinkedHashMap;import java.util.Map;/** * shiro配置项 */@Configurationpublic class ShiroConfiguration {// 适用于Spring的Bean后处理器自动调用实现 或接口的Shiro对象上的init()和/或// destroy()方法。这种后处理器使得在Spring中更容易配置Shiro// bean,因为用户从不必担心是否必须指定init-method和destroy-method bean属性。@Bean(name = "lifecycleBeanPostProcessor")public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {return new LifecycleBeanPostProcessor();}// 处理认证匹配处理器:如果自定义需要实现继承HashedCredentialsMatcher// 指定加密方式方式,也可以在这里加入缓存,当用户超过五次登陆错误就锁定该用户禁止不断尝试登陆@Bean(name = "hashedCredentialsMatcher")public HashedCredentialsMatcher hashedCredentialsMatcher() {HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();credentialsMatcher.setHashAlgorithmName("MD5");credentialsMatcher.setHashIterations(1);credentialsMatcher.setStoredCredentialsHexEncoded(true);return credentialsMatcher;}//认证实现@Bean(name = "shiroRealm")@DependsOn("lifecycleBeanPostProcessor")public ShiroRealm shiroRealm() {ShiroRealm realm = new ShiroRealm();realm.setCredentialsMatcher(hashedCredentialsMatcher());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<>();filterChainDefinitionManager.put("/logout", "logout");filterChainDefinitionManager.put("/index", "anon");filterChainDefinitionManager.put("/login", "anon");// anon 可以理解为不拦截filterChainDefinitionManager.put("/ajaxLogin", "anon");// anonfilterChainDefinitionManager.put("/apps/content", "user");filterChainDefinitionManager.put("/cms/content", "user");filterChainDefinitionManager.put("/sys/content", "user");filterChainDefinitionManager.put("/cms/article/add","perms[article:add]");filterChainDefinitionManager.put("/cms/article/edit.*","perms[article:edit]");// 可以理解为不拦截filterChainDefinitionManager.put("/static/**", "anon");// 静态资源不拦截filterChainDefinitionManager.put("/**", "authc");// 其他资源全部拦截(需登陆后才能查看)shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionManager);shiroFilterFactoryBean.setLoginUrl("/login");shiroFilterFactoryBean.setSuccessUrl("/");shiroFilterFactoryBean.setUnauthorizedUrl("/403");return shiroFilterFactoryBean;}@Bean@ConditionalOnMissingBeanpublic DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();daap.setProxyTargetClass(true);return daap;}@Beanpublic AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();aasa.setSecurityManager(securityManager);return aasa;}}
ShiroRealm.java
package com.jdy.conf;import java.util.ArrayList;import java.util.HashSet;import java.util.List;import java.util.Set;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.AuthenticationInfo;import org.apache.shiro.authc.AuthenticationToken;import org.apache.shiro.authc.SimpleAuthenticationInfo;import org.apache.shiro.authc.UsernamePasswordToken;import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.authz.SimpleAuthorizationInfo;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.session.Session;import org.apache.shiro.subject.PrincipalCollection;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import com.jdy.sys.model.SysRolePermission;import com.jdy.sys.model.SysUser;import com.jdy.sys.service.SysPermissionService;import com.jdy.sys.service.SysRolePermissionService;import com.jdy.sys.service.SysUserService;/** * 获取用户的角色和权限信息 */public class ShiroRealm extends AuthorizingRealm {private Logger logger = LoggerFactory.getLogger(ShiroRealm.class);@Autowiredprivate SysUserService sysUserService;@Autowiredprivate SysRolePermissionService sysRolePermissionService;@Autowiredprivate SysPermissionService sysPermissionService;/** * 登录认证 * * @param authenticationToken * @return * @throws AuthenticationException */@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)throws AuthenticationException {UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;logger.info("验证当前Subject时获取到token为:" + token.toString());// 查出是否有此用户SysUser user = sysUserService.findByNo(token.getUsername());if (user != null) { Session session = SecurityUtils.getSubject().getSession(); session.setAttribute("user", user);//成功则放入session// 若存在,将此用户存放到登录认证info中,无需自己做密码对比,Shiro会为我们进行密码对比校验return new SimpleAuthenticationInfo(user.getNo(),user.getPassword(), getName());}return null;}/** * 权限认证 * * @param principalCollection * @return */@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {logger.info("##################执行Shiro权限认证##################");// 获取当前登录输入的用户名,等价于(String)String loginName = (String) super.getAvailablePrincipal(principalCollection);// 到数据库查是否有此对象SysUser user = sysUserService.findByNo(loginName);if (user != null) {// 权限信息对象info,用来存放查出的用户的所有的角色(role)及权限(permission)SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();// 用户的角色集合Set<String> set = new HashSet<String>();set.add(user.getRname());info.setRoles(set);// 用户的权限集合List<SysRolePermission> srpList = sysRolePermissionService.selectByRid(user.getRid());List<String> pNameList = new ArrayList<String>();for (SysRolePermission sysRolePermission : srpList) {pNameList.add(sysPermissionService.selectByPrimaryKey(sysRolePermission.getPid()).getPermission());}info.addStringPermissions(pNameList);return info;}// 返回null的话,就会导致任何用户访问被拦截的请求时,都会自动跳转到unauthorizedUrl指定的地址return null;}}
五、LoginController
package com.jdy.sys.controller;import java.util.HashMap;import java.util.Map;import javax.annotation.Resource;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpSession;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.ExcessiveAttemptsException;import org.apache.shiro.authc.IncorrectCredentialsException;import org.apache.shiro.authc.LockedAccountException;import org.apache.shiro.authc.UnknownAccountException;import org.apache.shiro.authc.UsernamePasswordToken;import org.apache.shiro.subject.Subject;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.validation.BindingResult;import org.springframework.web.bind.annotation.ModelAttribute;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.ResponseBody;import org.springframework.web.servlet.ModelAndView;import org.springframework.web.servlet.mvc.support.RedirectAttributes;import com.jdy.sys.model.SysUser;import com.jdy.sys.service.SysUserService;import com.jdy.sys.util.Constant;import com.jdy.sys.util.SysUserUtils;import com.jdy.util.StringUtil;/** * @author LiuBang * * 2017年9月8日 下午5:16:17 */@Controllerpublic class LoginController {@Resourceprivate SysUserService sysUserService;private static final Logger logger = LoggerFactory.getLogger(LoginController.class);/** * 403无权限页面 * @param model * @param request * @return */@RequestMapping(value="/403")public String toError(Model model, HttpServletRequest request) {return "403";}/** * 管理主页 * * @param model * @param request * @return */@RequestMapping(value="/index")public String toIndex(Model model, HttpServletRequest request) {if( SysUserUtils.getSessionLoginUser() == null){return "login";}return "index";}/** * 跳转到登录页面 * * @return */@RequestMapping(value = "login", method = RequestMethod.GET)public String toLogin() {if( SysUserUtils.getSessionLoginUser() != null ){return "redirect:/index";}return "login";}/** * 登录验证 * * @param no 工号 * @param password 密码 * @return */@RequestMapping(value = "/login", method = RequestMethod.POST)public ModelAndView checkLogin(String no,String password) {ModelAndView mv=new ModelAndView(); String username = no; UsernamePasswordToken token = new UsernamePasswordToken(no, password); //获取当前的Subject Subject currentUser = SecurityUtils.getSubject(); try { //在调用了login方法后,SecurityManager会收到AuthenticationToken,并将其发送给已配置的Realm执行必须的认证检查 //每个Realm都能在必要时对提交的AuthenticationTokens作出反应 //所以这一步在调用login(token)方法时,它会走到MyRealm.doGetAuthenticationInfo()方法中,具体验证方式详见此方法 logger.info("对用户[" + username + "]进行登录验证..验证开始"); currentUser.login(token); logger.info("对用户[" + username + "]进行登录验证..验证通过"); }catch(UnknownAccountException uae){ logger.info("对用户[" + username + "]进行登录验证..验证未通过,未知账户"); mv.addObject("message", "未知账户"); }catch(IncorrectCredentialsException ice){ logger.info("对用户[" + username + "]进行登录验证..验证未通过,错误的凭证"); mv.addObject("message", "密码不正确"); }catch(LockedAccountException lae){ logger.info("对用户[" + username + "]进行登录验证..验证未通过,账户已锁定"); mv.addObject("message", "账户已锁定"); }catch(ExcessiveAttemptsException eae){ logger.info("对用户[" + username + "]进行登录验证..验证未通过,错误次数过多"); mv.addObject("message", "用户名或密码错误次数过多"); }catch(AuthenticationException ae){ //通过处理Shiro的运行时AuthenticationException就可以控制用户登录失败或密码错误时的情景 logger.info("对用户[" + username + "]进行登录验证..验证未通过,堆栈轨迹如下"); mv.addObject("message", "用户名或密码不正确"); ae.printStackTrace(); } //验证是否登录成功 if(currentUser.isAuthenticated()){ logger.info("用户[" + username + "]登录认证通过(这里可以进行一些认证通过后的一些系统参数初始化操作)"); mv.setViewName("/index"); }else{ token.clear(); mv.setViewName("/login"); } return mv;}/** * 用户退出 * * @return 跳转到登录页面 */@RequestMapping("logout")public String logout(RedirectAttributes redirectAttributes) { //使用权限管理工具进行用户的退出,跳出登录,给出提示信息 SecurityUtils.getSubject().logout(); redirectAttributes.addFlashAttribute("message", "您已安全退出"); return "redirect:/login";}}
阅读全文
1 0
- springboot-shrio-mybatis登录验证与权限控制
- Spring+MyBatis实践——登录与权限控制
- 【一】Springboot+Shiro+Mybatis+Thymeleaf实现权限控制和gif验证
- springboot+shiro+mybatis实现角色权限控制
- shiro-springmvc-mybatis登录认证 权限控制
- Spring security实现登录验证+权限控制
- shrio教程初级(八)shiro验证码与记住登录
- SpringBoot+shiro整合学习之登录认证和权限控制
- SpringBoot+shiro整合学习之登录认证和权限控制
- SpringBoot权限控制
- springboot系列(一):初次使用与登录验证实现
- TP 验证登录权限
- springboot与mybatis整合
- MyBatis与SpringBoot
- SpringBoot与Mybatis集成
- Shrio权限管理框架
- shrio验证cookie有效性
- Shrio授权验证详解
- 实现运动的尾巴效果
- 登录记住密码
- 转载:国学与古代文学的关系
- Vue2+VueRouter2+webpack 构建项目实战(三)配置路由,整俩页面先
- 深度解析阿里云存储
- springboot-shrio-mybatis登录验证与权限控制
- js 点击事件回调函数传参
- OpenStack Pike 版本中的 53 个新功能
- HDU 1010 dfs+奇偶剪枝
- BZOJ 1029 建筑抢修 贪心(替换)
- 局部最小的值(O(logn))
- 最新版TensorFlow 1.3 windows环境安装
- Java
- Java.util.logging日志入门教程(二)properties配置(输出文件)