ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[TOC] ## 1. 整合 mybatis+beetl+shiro+durid 实例代码: https://github.com/dailinlernhard/springboot 1. admin登录 ![](https://box.kancloud.cn/1ac0ad9e5725bfa0c5370e8116f0220e_559x304.png) ![](https://box.kancloud.cn/dfd7bfda931eaf02411e633dc0844904_632x281.png) **可以访问/listall** ![](https://box.kancloud.cn/ab87f844f270b8f4e6090340aa8ab8e1_686x640.png) 2. employee登录 ![](https://box.kancloud.cn/bcfe8befd508b61ccc2b7f3150223ea9_632x276.png) ![](https://box.kancloud.cn/99e450f31f0b1dbe39379e0f9bf3f140_892x240.png) **不能访问** ![](https://box.kancloud.cn/c608637c4c08bf7fbba2760c66ca45d4_1073x471.png) ## 2. shiro关键代码 > Realm > 1. doGetAuthorizationInfo: > 从数据库中读取权限信息,并注册到SecurityManager,通过注解和标签触发权限校验 > > 2. doGetAuthenticationInfo: > 从数据库中读取用户名和密码注册到SecurityManager,并由shiro完成用户登录的用户名和密码与数据库中的对比,完成用户登录验证 ~~~ @Component("aexitShrioRealm") public class AexitShrioRealm extends AuthorizingRealm { @Resource UserInfoService userService; @Resource RoleService roleService; @Resource PermissionService menuService; /** * 配置用户权限 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { if (principals == null) { throw new AuthorizationException("PrincipalCollection method argument cannot be null."); } String userId = (String) getAvailablePrincipal(principals); List<String> roleList = roleService.getRoles(userId); //用户角色获取用户功能id Set<String> roleSet = new HashSet<>(); //角色集合 Set<String> menuSet = new HashSet<>(); //菜单集合 List<String> menus; for(String roleId : roleList){ roleSet.add(roleId); menus = menuService.getPermissones(roleId); Collections.addAll(menuSet,menus.toArray(new String[menus.size()])); } SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(roleSet); authorizationInfo.setStringPermissions(menuSet); return authorizationInfo; } /** * 配置登录认证信息 * * @param authenticationToken * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; String userId = token.getUsername(); if (userId == null) { throw new AccountException("Null usernames are not allowed by this realm."); } //查出是否有此用户 Userinfo curUser = userService.findByUsername(userId); if(curUser == null) throw new AccountException("account error:one user name must have one and only one user! "); //密码加密 String password = ShiroKit.md5(curUser.getPassword(),curUser.getSalt()); return new SimpleAuthenticationInfo(userId, password, getName()); } } ~~~ ShiroConfiguration ~~~ /** * shiro生命周期配置项 */ @Configuration public class ShiroConfiguration { // @Resource // SysMenuExtMapper sysMenuExtMapper; @Bean(name = "lifecycleBeanPostProcessor") public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } @Bean(name = "shiroRealm") @DependsOn("lifecycleBeanPostProcessor") public AexitShrioRealm shiroRealm() { AexitShrioRealm realm = new AexitShrioRealm(); 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); Map<String, String> filterChainDefinitionManager = new LinkedHashMap<>(); filterChainDefinitionManager.put("/druid/**", "anon"); filterChainDefinitionManager.put("/static/**", "anon");//静态资源不拦截 filterChainDefinitionManager.put("/login", "anon");//anon 可以理解为不拦截 filterChainDefinitionManager.put("/logout", "anon");//anon 可以理解为不拦截 filterChainDefinitionManager.put("/kaptcha", "anon");//anon 可以理解为不拦截 filterChainDefinitionManager.put("/", "anon"); filterChainDefinitionManager.put("/**", "authc");//authc未登录拦截 myperm 菜单url权限拦截 shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionManager); shiroFilterFactoryBean.setLoginUrl("/"); //shiroFilterFactoryBean.setSuccessUrl("/"); shiroFilterFactoryBean.setUnauthorizedUrl("/"); //设置未通过,跳转URL 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; } //thymeleaf模板引擎和shiro整合时使用 /*@Bean(name = "shiroDialect") public ShiroDialect shiroDialect(){ return new ShiroDialect(); }*/ } ~~~ ## 2. 记住我 1. 登录信息存储在cookie中 2. 权限对用户的校验依然起作用 Shiro记住密码 记住密码实现起来也是比较简单的,主要看下是如何实现的。 **在ShiroConfiguration加入两个方法:** ~~~ /** * cookie对象; * @return */ @Bean public SimpleCookie rememberMeCookie(){ System.out.println("ShiroConfiguration.rememberMeCookie()"); //这个参数是cookie的名称,对应前端的checkbox的name = rememberMe SimpleCookie simpleCookie = new SimpleCookie("rememberMe"); //<!-- 记住我cookie生效时间30天 ,单位秒;--> simpleCookie.setMaxAge(259200); returnsimpleCookie; } /** * cookie管理对象; * @return */ @Bean public CookieRememberMeManager rememberMeManager(){ System.out.println("ShiroConfiguration.rememberMeManager()"); CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager(); cookieRememberMeManager.setCookie(rememberMeCookie()); returncookieRememberMeManager; } ~~~ 将rememberMeManager注入到SecurityManager中 ~~~ @Bean public SecurityManager securityManager(){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); //设置realm. securityManager.setRealm(myShiroRealm()); //注入缓存管理器; securityManager.setCacheManager(ehCacheManager());//这个如果执行多次,也是同样的一个对象; //注入记住我管理器; securityManager.setRememberMeManager(rememberMeManager()); returnsecurityManager; } ~~~ 在ShiroFilterFactoryBean添加记住我过滤器: ~~~ @Bean public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager){ System.out.println("ShiroConfiguration.shirFilter()"); ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); // 必须设置 SecurityManager shiroFilterFactoryBean.setSecurityManager(securityManager); //拦截器. Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>(); //配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了 filterChainDefinitionMap.put("/logout", "logout"); //配置记住我或认证通过可以访问的地址 filterChainDefinitionMap.put("/index", "user"); filterChainDefinitionMap.put("/", "user"); //<!-- 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了; //<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问--> filterChainDefinitionMap.put("/**", "authc"); // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面 shiroFilterFactoryBean.setLoginUrl("/login"); // 登录成功后要跳转的链接 shiroFilterFactoryBean.setSuccessUrl("/index"); //未授权界面; shiroFilterFactoryBean.setUnauthorizedUrl("/403"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); returnshiroFilterFactoryBean; } ~~~ 主要是加入了: //配置记住我或认证通过可以访问的地址 ~~~ filterChainDefinitionMap.put("/index", "user"); filterChainDefinitionMap.put("/", "user"); ~~~ 修改登录界面加入rememberMe复选框: 在login.html中加入: ~~~ <P><input type="checkbox" name="rememberMe" />记住我</P> ~~~ 关闭浏览器,重新打开浏览器,admin就可以访问http://localhost:8090/listall ,不用登录,employee就不行了 ![](https://box.kancloud.cn/929fca4c374ae9f3c99b403da5852b95_581x634.png)