springboot整合Apache Shiro

xiaoxiao2021-02-28  16

Apache Shiro Features 特性 Authentication(认证), Authorization(授权), Session Management(会话管理), Cryptography(加密)被 Shiro 框架的开发团队称之为应用安全的四大基石。那么就让我们来看看它们吧: Authentication(认证):用户身份识别,通常被称为用户“登录” Authorization(授权):访问控制。比如某个用户是否具有某个操作的使用权限。 Session Management(会话管理):特定于用户的会话管理,甚至在非web 或 EJB 应用程序。 Cryptography(加密):在对数据源使用加密算法加密的同时,保证易于使用。 High-Level Overview 高级概述 在概念层,Shiro 架构包含三个主要的理念:Subject,SecurityManager和 Realm。 Subject:当前用户,Subject 可以是一个人,但也可以是第三方服务、守护进程帐户、时钟守护任务或者其它–当前和软件交互的任何事件。 SecurityManager:管理所有Subject,SecurityManager 是 Shiro 架构的核心,配合内部安全组件共同组成安全伞。 Realms:用于进行权限信息的验证,我们自己实现。Realm 本质上是一个特定的安全 DAO:它封装与数据源连接的细节,得到Shiro 所需的相关的数据。在配置 Shiro 的时候,你必须指定至少一个Realm 来实现认证(authentication)和/或授权(authorization)。 我们需要实现Realms的Authentication 和 Authorization。其中 Authentication 是用来验证用户身份,Authorization 是授权访问控制,用于对用户进行的操作授权,证明该用户是否允许进行当前操作,如访问某个链接,某个资源文件等。 pom包依赖 pom.xml <shiro.version>1.3.2</shiro.version>  <dependency>             <groupId>com.zteict.baseplatform</groupId>             <artifactId>shiro-spring-boot-starter</artifactId>             <version>${zteict-stater.version}</version>  </dependency>  Shiro 配置 首先要配置的是ShiroConfig类,Apache Shiro 核心通过 Filter 来实现,就好像SpringMvc 通过DispachServlet 来主控制一样。 既然是使用 Filter 一般也就能猜到,是通过URL规则来进行过滤和权限校验,所以我们需要定义一系列关于URL的规则和访问权限。 MyShiroConfig.java  package com.zteict; import java.util.LinkedHashMap; import java.util.Map; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.HandlerExceptionResolver; @Configuration public class MyShiroConfig { @Bean     public ShiroFilterFactoryBean shirFilter(org.apache.shiro.mgt.SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();         // 必须设置 SecurityManager         shiroFilterFactoryBean.setSecurityManager(securityManager);         // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面         shiroFilterFactoryBean.setLoginUrl("/login");         // 登录成功后要跳转的链接         shiroFilterFactoryBean.setSuccessUrl("/index");         // 未授权界面;         //shiroFilterFactoryBean.setUnauthorizedUrl("/test/unauthorized");         // 拦截器.         Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();         // 配置不会被拦截的链接 顺序判断         filterChainDefinitionMap.put("/css/**", "anon");         filterChainDefinitionMap.put("/img/**", "anon");         filterChainDefinitionMap.put("/js/**", "anon");         filterChainDefinitionMap.put("/login", "anon");         filterChainDefinitionMap.put("/ajaxlogin", "anon");         // 配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了         filterChainDefinitionMap.put("/logout", "logout");         //filterChainDefinitionMap.put("/add", "perms[权限添加]");         // <!-- 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;         // <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->         filterChainDefinitionMap.put("/**", "authc");         shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);         return shiroFilterFactoryBean;     }       @Bean     public MyPrincipalAuthorizingRealm myShiroRealm(){         return new MyPrincipalAuthorizingRealm();     }         @Bean     public  org.apache.shiro.mgt.SecurityManager securityManager(){         DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();         securityManager.setRealm(myShiroRealm());         return securityManager;     }               @Bean       public HandlerExceptionResolver solver(){           HandlerExceptionResolver handlerExceptionResolver=new MyExceptionResolver();           return handlerExceptionResolver;       }        } Filter Chain定义说明: 1、一个URL可以配置多个Filter,使用逗号分隔 2、当设置多个过滤器时,全部验证通过,才视为通过 3、部分过滤器可指定参数,如perms,roles Shiro内置的FilterChain anon:所有url都都可以匿名访问 authc: 需要认证才能进行访问 user:配置记住我或认证通过可以访问 登录认证实现 在认证、授权内部实现机制中都有提到,最终处理都将交给Real进行处理。因为在Shiro中,最终是通过Realm来获取应用程序中的用户、角色及权限信息的。通常情况下,在Realm中会直接从我们的数据源中获取Shiro需要的验证信息。可以说,Realm是专用于安全框架的DAO. Shiro的认证过程最终会交由Realm执行,这时会调用Realm的getAuthenticationInfo(token)方法。 该方法主要执行以下操作: 1、检查提交的进行认证的令牌信息 2、根据令牌信息从数据源(通常为数据库)中获取用户信息 3、对用户信息进行匹配验证。 4、验证通过将返回一个封装了用户信息的AuthenticationInfo实例。 5、验证失败则抛出AuthenticationException异常信息。 而在我们的应用程序中要做的就是自定义一个Realm类,继承AuthorizingRealm抽象类,重载doGetAuthenticationInfo(),重写获取用户信息的方法。 doGetAuthenticationInfo的重写 MyPrincipalAuthorizingRealm.java package com.zteict; import java.util.List; import javax.annotation.Resource; 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.authz.UnauthorizedException; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.springframework.stereotype.Component; import com.zteict.dao.AppPermissionMapper; import com.zteict.dao.AppUserMapper; import com.zteict.entity.AppRole; import com.zteict.entity.AppUser; @Component public class MyPrincipalAuthorizingRealm extends AuthorizingRealm { @Resource AppUserMapper appUserMapper; @Resource AppPermissionMapper appPermissionMapper; protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { UsernamePasswordToken usertoken=(UsernamePasswordToken) token; String userName = usertoken.getUsername(); // String userName = (String) token.getPrincipal();         AppUser user = appUserMapper.getAppUser(userName);         if (user == null) {              throw new UnauthorizedException("用户未登陆");         }                  SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPwd(),this.getName());         return info; } protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { AppUser user = (AppUser) principals.getPrimaryPrincipal();   if(user!=null){               SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();               //角色   List<AppRole> roleList; roleList = appPermissionMapper.getRolesByUser(user.getUserCode()); for (AppRole role:roleList) {                   info.addRole(role.getRoleName());               }                               //权限               /*List<Permission> permissions = permissionService.getPermissionByRoleId(user.getUserId());               for (Permission p : permissions){                   info.addStringPermission(String.valueOf(p.getPermissionId()));               }  */             return info;           }   return null; } } 链接权限的实现 shiro的权限授权是通过继承AuthorizingRealm抽象类,重载doGetAuthorizationInfo();当访问到页面的时候,链接配置了相应的权限或者shiro标签才会执行此方法否则不会执行,所以如果只是简单的身份认证没有权限的控制的话,那么这个方法可以不进行实现,直接返回null即可。在这个方法中主要是使用类:SimpleAuthorizationInfo进行角色的添加和权限的添加。 登录实现  @PostMapping("/ajaxlogin")     @ResponseBody     public Message login(@RequestBody AppUser user) throws IOException {     Message msg = new Message();     Subject currentUser = SecurityUtils.getSubject();     if ( currentUser.isAuthenticated() )     currentUser.logout();     if ( !currentUser.isAuthenticated() ) {     UsernamePasswordToken token = new UsernamePasswordToken(user.getUserCode(), user.getPwd());     //token.setRememberMe(true);     try {     currentUser.login(token);     } catch(Exception e) {   msg.setFlag(false); msg.setDesc(MessageTip.NO_USER);            return msg;          }       }     msg.setFlag(true);     return msg;       } 授权实现 @RequiresRoles("admin") @RequestMapping("/openAuthor") @ResponseBody public ModelAndView openAuthor(@RequestParam(required=true,defaultValue = "0") String roleId) throws IOException { ModelAndView  m = new ModelAndView (); m.setViewName("common/open/openAuthorWindow"); m.addObject("roleId", roleId); return m; } 报错页面处理 MyExceptionResolver.java package com.zteict; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.shiro.authz.UnauthorizedException; import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.ModelAndView; public class MyExceptionResolver implements HandlerExceptionResolver{ public ModelAndView resolveException(HttpServletRequest request,                 HttpServletResponse response, Object handler, Exception ex) {              if(ex instanceof UnauthorizedException){                 ModelAndView mv = new ModelAndView("error/403");                 return mv;             }             ModelAndView mv = new ModelAndView("error/500");             mv.addObject("exception", ex.toString().replaceAll("\n", "<br/>"));             return mv;         }   }
转载请注明原文地址: https://www.6miu.com/read-2650317.html

最新回复(0)