一、权限框架介绍
1. 权限治理
实质:用户身份认证+受权
流程:用户首先通过身份认证,通过后即可拜访该资源
1.1 用户身份认证
1.2 受权流程
2. 权限框架
Shiro和Spring Security比拟
(1)Shiro比Spring更容易应用,实现和了解
(2)Spring Security有更好的社区反对
(3)Apache Shiro在Spring Security解决密码学方面有一个额定的模块
(4)Spring-security 对spring 联合较好,如果我的项目用的springmvc ,应用起来很不便。然而如果我的项目中没有用到spring,那就不要思考它了。
(5)Shiro 功能强大、且 简略、灵便。是Apache 下的我的项目比拟牢靠,且不跟任何的框架或者容器绑定,能够独立运行
二、Shiro根底介绍
1. Shiro三个外围组件
1.1 Subject(以后操作用户)
不仅仅指人,也能够是第三方过程、后盾帐户(Daemon Account)或其余相似事物。Subject代表了以后用户的平安操作,SecurityManager则治理所有用户的平安操作。
1.2 SecurityManager(保护核心)
Shiro框架的外围,典型的Facade模式,用来协调外部组件实例,并提供平安治理的各种服务。
1.3 Realm(数据中心)
对用户认证(登录)和受权(访问控制)时,Shiro会从配置的Realm中查找用户及其权限信息。
当配置Shiro时,至多指定一个Realm,用于认证和(或)受权。配置多个Realm是能够的,然而至多须要一个。
Shiro内置了能够连贯大量平安数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、相似INI的文本配置资源以及属性文件等。如果缺省的Realm不能满足需要,你还能够插入代表自定义数据源的本人的Realm实现。
2. Shiro相干类介绍
(1)Authentication 认证 ---- 用户登录
(2)Authorization 受权 --- 用户具备哪些权限
(3)Cryptography 平安数据加密
(4)Session Management 会话治理
(5)Web Integration web系统集成
(6)Interations 集成其它利用,spring、缓存框架
3. Shiro 特点
(1)易于了解的 Java Security API;
(2)简略的身份认证(登录),反对多种数据源(LDAP,JDBC,Kerberos,ActiveDirectory 等);
(3)对角色的简略的签权(访问控制),反对细粒度的签权;
(4)反对一级缓存,以晋升应用程序的性能;
(5)内置的基于 POJO 企业会话治理,实用于 Web 以及非 Web 的环境;
(6)异构客户端会话拜访;
(7)非常简单的加密 API;
(8)不跟任何的框架或者容器捆绑,能够独立运行
三、Spring Boot整合Shiro代码实战
3.1 pom.xml中增加依赖
<dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope></dependency><dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.3.2</version></dependency>
3.2 编写测试Controller类
@RequiresPermissions("user:list")@RequiresRoles("admin")@ResponseBody@RequestMapping("/hello")public String hello(){ System.out.println(person); return "hello world";}@RequestMapping(value = "/login", method = RequestMethod.GET)@ResponseBodypublic String defaultLogin() { return "首页";}@RequestMapping(value = "/login", method = RequestMethod.POST)@ResponseBodypublic String login(@RequestParam("username") String username, @RequestParam("password") String password) { // 从SecurityUtils里边创立一个 subject Subject subject = SecurityUtils.getSubject(); // 在认证提交前筹备 token(令牌) UsernamePasswordToken token = new UsernamePasswordToken(username, password); // 执行认证登陆 try { subject.login(token); } catch (UnknownAccountException uae) { return "未知账户"; } catch (IncorrectCredentialsException ice) { return "明码不正确"; } catch (LockedAccountException lae) { return "账户已锁定"; } catch (ExcessiveAttemptsException eae) { return "用户名或明码谬误次数过多"; } catch (AuthenticationException ae) { return "用户名或明码不正确!"; } if (subject.isAuthenticated()) { return "登录胜利"; } else { token.clear(); return "登录失败"; }}
3.3 配置类
@Bean(name = "shiroFilter")public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); shiroFilterFactoryBean.setSecurityManager(securityManager); //增加Shiro内置过滤器 /** * Shiro内置过滤器,能够实现权限相干的拦截器 * 罕用的过滤器: * anon: 无需认证(登录)能够拜访 * authc: 必须认证才能够拜访 * user: 如果应用rememberMe的性能能够间接拜访 * perms: 该资源必须失去资源权限才能够拜访 * role: 该资源必须失去角色权限才能够拜访 */ shiroFilterFactoryBean.setLoginUrl("/login");//登录页 shiroFilterFactoryBean.setUnauthorizedUrl("/notRole"); Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); // <!-- authc:所有url都必须认证通过才能够拜访; anon:所有url都都能够匿名拜访--> filterChainDefinitionMap.put("/webjars/**", "anon"); filterChainDefinitionMap.put("/login", "anon"); filterChainDefinitionMap.put("/", "anon"); filterChainDefinitionMap.put("/front/**", "anon"); filterChainDefinitionMap.put("/api/**", "anon"); filterChainDefinitionMap.put("/admin/**", "authc"); filterChainDefinitionMap.put("/user/**", "authc"); filterChainDefinitionMap.put("/hello/**","perms[user:add]"); //次要这行代码必须放在所有权限设置的最初,不然会导致所有 url 都被拦挡 残余的都须要认证 filterChainDefinitionMap.put("/**", "authc"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean;}@Beanpublic DefaultWebSecurityManager securityManager() { DefaultWebSecurityManager defaultSecurityManager = new DefaultWebSecurityManager(); defaultSecurityManager.setRealm(customRealm()); DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO(); DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator(); defaultSessionStorageEvaluator.setSessionStorageEnabled(false); subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator); defaultSecurityManager.setSubjectDAO(subjectDAO); return defaultSecurityManager;}@Bean@DependsOn("lifecycleBeanPostProcessor")public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); defaultAdvisorAutoProxyCreator.setProxyTargetClass(true); return defaultAdvisorAutoProxyCreator;}@Beanpublic LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor();}@Beanpublic AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager()); return authorizationAttributeSourceAdvisor;}@Beanpublic CustomRealm customRealm() { CustomRealm customRealm = new CustomRealm(); return customRealm;}
3.4 Realm
/** * 权限认证,即登录过后,每个身份不肯定,对应的所能看的页面也不一样。 * @param principalCollection * @return */@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { User user = null; String username = ""; if (Objects.nonNull(principalCollection)){ user = (User)principalCollection.getPrimaryPrincipal(); } username = (String) SecurityUtils.getSubject().getPrincipal(); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); //用户角色 Set<String> roleSets = new HashSet<>(); roleSets.add("admin"); roleSets.add("test"); info.setRoles(roleSets); //角色对应的权限 Set<String> permissionSet = new HashSet<>(); permissionSet.add("user:show"); permissionSet.add("user:admin"); info.addStringPermissions(permissionSet); return info;}/** * 身份认证。即登录通过账号和明码验证登陆人的身份信息。 * @param authenticationToken * @return * @throws AuthenticationException */@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { System.out.println("-------身份认证办法--------"); //authenticationToken.getCredentials()----token?如何来? String token = (String) authenticationToken.getCredentials(); if (StringUtils.isEmpty(token)){ HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest(); Map<String, String[]> parameterMap = request.getParameterMap(); Set<Map.Entry<String, String[]>> entrys = parameterMap.entrySet(); for (Map.Entry<String, String[]> entry:entrys) { System.out.println(entry.getKey()+"============"+entry.getValue()); } throw new AuthenticationException("token为空"); } User user = this.checkAuthenticationToken(token); //String userName = (String) authenticationToken.getPrincipal(); //String userPwd = new String((char[]) authenticationToken.getCredentials()); return new SimpleAuthenticationInfo(user, token,getName());}