两个基本的概念前端
安全实体:系统须要保护的具体对象数据java
权限:系统相关的功能操做,例如基本的CRUDweb
Shiro spring
首先Shiro较之 Spring Security,Shiro在保持强大功能的同时,还在简单性和灵活性方面拥有巨大优点。数据库
Shiro是一个强大而灵活的开源安全框架,可以很是清晰的处理认证、受权、管理会话以及密码加密。以下是它所具备的特色:apache
Shiro四大核心功能:Authentication,Authorization,Cryptography,Session Management缓存
Shiro架构安全
Shiro三个核心组件:Subject, SecurityManager 和 Realms.架构
Subject:主体,能够看到主体能够是任何能够与应用交互的 “用户”;app
Realm:域,Shiro从从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它须要从Realm获取相应的用户进行比较以肯定用户身份是否合法;也须要从Realm获得用户相应的角色/权限进行验证用户是否能进行操做;能够把Realm当作DataSource,即安全数据源。
两个配置类ShiroConfig和UserRealm
1 package com.example.shirodemo.config; 2 3 import at.pollux.thymeleaf.shiro.dialect.ShiroDialect; 4 import org.apache.shiro.spring.web.ShiroFilterFactoryBean; 5 import org.apache.shiro.web.mgt.DefaultWebSecurityManager; 6 import org.springframework.beans.factory.annotation.Qualifier; 7 import org.springframework.context.annotation.Bean; 8 import org.springframework.context.annotation.Configuration; 9 10 import java.util.LinkedHashMap; 11 import java.util.Map; 12 13 /** 14 * shiro配置类 15 */ 16 @Configuration 17 public class ShiroConfig { 18 /** 19 * 建立ShiroFilterFactoryBean 20 */ 21 @Bean 22 public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){ 23 ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean(); 24 //设置安全管理器 25 shiroFilterFactoryBean.setSecurityManager(securityManager); 26 //添加Shiro拦截器 27 /** 28 * Shiro 内置过滤器,能够实现权限相关的拦截器 29 * anon:无需认证(登陆)能够直接访问 30 * authc:必须认证才能访问 31 * user:若是使用rememberMe的功能才能够访问 32 * perms:该资源获得资源权限才能够访问 33 * role:该资源必须获得角色权限才能够访问 34 */ 35 Map<String,String> filterMap=new LinkedHashMap<>(); 36 /* filterMap.put("/add","authc"); 37 filterMap.put("/update","authc");*/ 38 // filterMap.put("/test","anon"); 39 filterMap.put("/login","anon"); 40 //添加Shiro受权拦截器 41 filterMap.put("/add","perms[添加]"); 42 filterMap.put("/foresee","perms[预言将来]"); 43 filterMap.put("/update","perms[修改]"); 44 filterMap.put("/delete","perms[删除]"); 45 //filterMap.put("/update","perms[]"); 46 //filterMap.put("/delete","perms[]"); 47 //filterMap.put("/getAll","perms[]"); 48 filterMap.put("/*","authc"); 49 //跳转到登录的页面 50 shiroFilterFactoryBean.setLoginUrl("/tologin"); 51 //设置未受权的页面 52 shiroFilterFactoryBean.setUnauthorizedUrl("/unAuth"); 53 shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap); 54 55 return shiroFilterFactoryBean; 56 } 57 /** 58 * 建立DefaultWebSecurityManager 59 */ 60 @Bean("securityManager") 61 public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){ 62 DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager(); 63 //关联Realm 64 securityManager.setRealm(userRealm); 65 return securityManager; 66 } 67 /** 68 * 建立Realm 69 */ 70 @Bean("userRealm") 71 public UserRealm getRealm(){ 72 UserRealm userRealm=new UserRealm(); 73 return userRealm; 74 } 75 /** 76 * 配置shiroDialect,用于thymeleaf和shiro标签配合使用 77 */ 78 @Bean 79 public ShiroDialect getShiroDialect(){ 80 ShiroDialect shiroDialect=new ShiroDialect(); 81 return shiroDialect; 82 } 83 }
package com.example.shirodemo.config; import com.example.shirodemo.bean.Permission; import com.example.shirodemo.bean.User; import com.example.shirodemo.service.IPermissionService; import com.example.shirodemo.service.IUserService; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.Subject; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import javax.annotation.Resource; import java.util.ArrayList; import java.util.List; /** * 自定义Realm */ public class UserRealm extends AuthorizingRealm { @Resource private IUserService userService; @Resource private IPermissionService permissionService; /** * 执行受权逻辑 * @param principalCollection * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { System.out.println("执行受权逻辑"); /** * 给资源受权 */ SimpleAuthorizationInfo simpleAuthorizationInfo=new SimpleAuthorizationInfo(); //添加受权字符串 //simpleAuthorizationInfo.addStringPermission("user:add"); //--------------------认证帐号 Subject subject= SecurityUtils.getSubject(); User user=(User)subject.getPrincipal(); User user1=userService.findById(user.getId()); if(user1==null){ //用户名不存在 return null; } //-------------------开始受权 List<Permission> permissions =permissionService.getPermissionByUserId(user1.getId()); for (Permission per : permissions) { simpleAuthorizationInfo.addStringPermission(per.getName()); System.out.println("拥有权限:"+per.getName()); } return simpleAuthorizationInfo; } /** * 执行认证逻辑 * @param authenticationToken * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { System.out.println("执行认证逻辑"); /** * 判断ShiroRealm逻辑UsernamePasswordToken是否正确 */ //1判断用户名 UsernamePasswordToken usernamePasswordToken=(UsernamePasswordToken)authenticationToken; User user=userService.findByname(usernamePasswordToken.getUsername()); if(user==null){ //用户名不存在 return null; } //判断密码是否正确 return new SimpleAuthenticationInfo(user,user.getPassword(),""); } }
认证过程
1 /** 2 * 登陆逻辑处理 3 */ 4 @RequestMapping("/login") 5 public String login(User user, Model model) { 6 /** 7 *使用shiro编写认证操做 8 */ 9 //1:获取subject 10 Subject subject = SecurityUtils.getSubject(); 11 //2:封装用户帐号和密码 12 UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(user.getUsername(), user.getPassword()); 13 //3:执行登陆方法 14 try { 15 subject.login(usernamePasswordToken); 16 model.addAttribute(user); 17 //登陆成功 18 //成功后跳转到 19 //return "redirect:/test"; 20 return "/test"; 21 } catch (UnknownAccountException e) { 22 //e.printStackTrace(); 23 //登陆失败用户名不存在 24 model.addAttribute("msg","用户名不存在"); 25 return "login"; 26 }catch (IncorrectCredentialsException e){ 27 //登陆失败密码错误 28 model.addAttribute("msg","密码错误"); 29 return "login"; 30 } 31 } 32 }
Subject拿到用户数据后走UserRealm 类里面的认证逻辑,受权过程比较简单能够看你上面的代码,
Shiro配置拦截器
//添加Shiro拦截器
27 /**
28 * Shiro 内置过滤器,能够实现权限相关的拦截器
29 * anon:无需认证(登陆)能够直接访问
30 * authc:必须认证才能访问
31 * user:若是使用rememberMe的功能才能够访问
32 * perms:该资源获得资源权限才能够访问
33 * role:该资源必须获得角色权限才能够访问
34 */
Spring Security
除了不能脱离Spring,shiro的功能它都有。并且Spring Security对Oauth、OpenID也有支持,Shiro则须要本身手动实现。Spring Security的权限细粒度更高,毕竟Spring Security是Spring家族的。
Spring Security通常流程为:
①当用户登陆时,前端将用户输入的用户名、密码信息传输到后台,后台用一个类对象将其封装起来,一般使用的是UsernamePasswordAuthenticationToken这个类。
②程序负责验证这个类对象。验证方法是调用Service根据username从数据库中取用户信息到实体类的实例中,比较二者的密码,若是密码正确就成功登录,同时把包含着用户的用户名、密码、所具备的权限等信息的类对象放到SecurityContextHolder(安全上下文容器,相似Session)中去。
③用户访问一个资源的时候,首先判断是不是受限资源。若是是的话还要判断当前是否未登陆,没有的话就跳到登陆页面。
④若是用户已经登陆,访问一个受限资源的时候,程序要根据url去数据库中取出该资源所对应的全部能够访问的角色,而后拿着当前用户的全部角色一一对比,判断用户是否能够访问。
注:
OAuth在"客户端"与"服务提供商"之间,设置了一个受权层(authorization layer)。"客户端"不能直接登陆"服务提供商",只能登陆受权层,以此将用户与客户端区分开来。"客户端"登陆受权层所用的令牌(token),与用户的密码不一样。用户能够在登陆的时候,指定受权层令牌的权限范围和有效期。
"客户端"登陆受权层之后,"服务提供商"根据令牌的权限范围和有效期,向"客户端"开放用户储存的资料。
OpenID 系统的第一部分是身份验证,即如何经过 URI 来认证用户身份。目前的网站都是依靠用户名和密码来登陆认证,这就意味着你们在每一个网站都须要注册用户名和密码,即使你使用的是一样的密码。若是使用 OpenID ,你的网站地址(URI)就是你的用户名,而你的密码安全的存储在一个 OpenID 服务网站上(你能够本身创建一个 OpenID 服务网站,也能够选择一个可信任的 OpenID 服务网站来完成注册)。
与OpenID同属性的身份识别服务商还有ⅥeID,ClaimID,CardSpace,Rapleaf,Trufina ID Card等,其中ⅥeID通用帐户的应用最为普遍。
Spring Security和Shiro
相同点:
1:认证功能
2:受权功能
3:加密功能
4:会话管理
5:缓存支持
6:rememberMe功能.......
不一样点:
优势:
1:Spring Security基于Spring开发,项目中若是使用Spring做为基础,配合Spring Security作权限更加方便,而Shiro须要和Spring进行整合开发
2:Spring Security功能比Shiro更加丰富些,例如安全防御
3:Spring Security社区资源比Shiro丰富
缺点:
1:Shiro的配置和使用比较简单,Spring Security上手复杂
2:Shiro依赖性低,不须要任何框架和容器,能够独立运行,而Spring Security依赖于Spring容器