One:Shiro的认证与授权

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Sugar_map/article/details/81037365

本文核心:RBAC权限模型,Shiro与Spring的整合,Shiro认证与授权【集成到项目中】。

 

这系列博客是记录自己做过项目学到知识。one、two代表项目编号。

 

前言:

后台管理系统

技术选型:ssm + easyui + ajax + js/jq + jsp + mysql + redis + webservice

工具版本:jdk1.8 + tomcat7/8 + mysql8.0.11 + idea2017 + spring4.1.13

项目规范:maven3.3.9 + git

shiro认证与授权可以通过配置shiro.ini文件。这里采用Shrio与Spring项目集成的方式,将Shiro的配置文件配置到Spring配置文件中。

一:RBAC权限模型【管理系统权限】

首先介绍一下,什么是认证,什么是授权。


认证:

Subject:主体

访问系统的用户,主体可以是用户、程序等,进行认证的都称为主体。

Principal:身份信息

是主体(subject)进行身份认证的标识,标识必须具有唯一性,如用户名、手机号、邮箱地址等,一个主体可以有多个身份,但是必须有一个主身份(Primary Principal)。

credential:凭证信息

是只有主体自己知道的安全信息,如密码、证书等。

token(令牌):身份信息+凭证信息的组合=一个令牌


授权:

Who,即主体Subject),主体需要访问系统中的资源。

What,即资源(Resource),如系统菜单、页面、按钮、类方法、系统商品信息等。资源包括资源类型和资源实例,比如商品信息为资源类型,类型为t01的商品为资源实例,编号为001的商品信息也属于资源实例。

How,权限/许可(Permission),规定了主体对资源的操作许可,权限离开资源没有意义,如用户查询权限、用户添加权限、某个类方法的调用权限、编号为001用户的修改权限等,通过权限可知主体对哪些资源都有哪些操作许可



RBAC认为权限的过程可以抽象概括为:判断【Who是否可以对What进行How的访问操作(Operator)】这个逻辑表达式的值是否为True的求解过程。

即将权限问题转换为Who、What、How的问题。who、what、how构成了访问权限三元组。

权限模型:

我们的数据库权限设计,需要五张表。这张图我已经详细解释了如何查询用户的角色和权限。【不补充数据库设计和Mapper文件的写法。】



二:Shiro与Spring整合   


首先导入Shiro依赖和Shiro与Spring整合依赖 【默认已完成SSM项目框架搭建】

<!-- shiro core与Web集成的依赖 -->
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-core -->
<dependency>
   <groupId>org.apache.shiro</groupId>
   <artifactId>shiro-core</artifactId>
   <version>1.3.1</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-web -->
<dependency>
   <groupId>org.apache.shiro</groupId>
   <artifactId>shiro-web</artifactId>
   <version>1.3.1</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring -->
<dependency>
   <groupId>org.apache.shiro</groupId>
   <artifactId>shiro-spring</artifactId>
   <version>1.3.1</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-ehcache -->
<dependency>
   <groupId>org.apache.shiro</groupId>
   <artifactId>shiro-ehcache</artifactId>
   <version>1.2.6</version>
</dependency>


Web.xml配置 shiro的过滤器【Filter过滤器配置顺序即调用链传递的顺序,个人建议:如果配置SpringMVC自带的字符过滤器应放在Shiro过滤器前面。

<!--配置shir的过滤器-->
<filter>
   <filter-name>shiroFilter</filter-name>
   <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
   <init-param>
      <param-name>targetBeanName</param-name>
      <param-value>shiroFilter</param-value>
   </init-param>
</filter>
<filter-mapping>
   <filter-name>shiroFilter</filter-name>
   <url-pattern>/*</url-pattern>
</filter-mapping>

其中的<init-param></init-param>  配置指向 application-context-shiro.xml的配置文件的一个bean


application-context-shiro.xml的配置文件

<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!--配置安全管理工厂-->
   <!--配置安全工厂-->
   <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
      <!--配置登陆验证与授权的myRealm-->
      <property name="realms">
         <list>
            <ref bean="myRealm"></ref>
         </list>
      </property>
   </bean>

   <!--匹配器对象 并配置复杂匹配器-->
   <bean id="myRealm" class="com.baizhi.util.MyRealm">
      <property name="credentialsMatcher" ref="credentialsMatcher"></property>
   </bean>

   <!--声明复杂的凭证匹配器对象-->
   <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
      <!--加密算法-->
      <property name="hashAlgorithmName" value="md5"></property>
      <!--迭代加密次数-->
      <property name="hashIterations" value="1024"></property>
   </bean>


   <!--shiro过滤对象工厂对象 负责校验  处理请求的bean
      【区分】限制资源的访问【主要判断用户是否认证,重点:认证】
   -->
   <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
      <property name="securityManager" ref="securityManager"/>
      <!--登录页的Url  验证失败 重定向的Url-->
      <property name="loginUrl" value="/Login_Jsp/login.jsp"/>
      <!--             产生异常 重定向的Url-->
      <property name="unauthorizedUrl" value="/error.jsp"/>
      <property name="filterChainDefinitions" >
      <!--
         定义过滤器链的拦截规则
         从上到下,满足则执行。
          url=过滤器简称
          过滤器:anon |不认证就可以访问资源
               authc |必须认证才可以访问资源【不支持记住我功能】
                user |认证成功或记住我【放行】 可访问资源
               logout|登出过滤器
               roles |角色授权过滤器
                perms|权限授权过滤器
      -->
         <value>
            /Login_Jsp/login.jsp=anon
            /Main_Jsp/main/main.jsp=authc
            /**=anon
         </value>
      </property>
   </bean>

</beans>


重点理解掌握 过滤器的取值的含义

         过滤器:anon |不认证就可以访问资源
               authc |必须认证才可以访问资源【不支持记住我功能】
                user |认证成功或记住我【放行】 可访问资源
               logout|登出过滤器
               roles |角色授权过滤器
                perms|权限授权过滤器
提示:我们将 Shiro的配置单独为一个文件,因此需要将Shiro的配置文件导入Spring配置文件中。【代码省略】



三:自定义复杂的凭证匹配器

MyRealm 继承AuthorizingRealm 类,需要实现两个抽象方法。

protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)//认证方法
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection)//授权方法


认证的过程:

①Controller接收参数用户名密码,web环境下获取主体,调用主体的Login方法。

        @RequestMapping("/login")
	public @ResponseBody String managerLogin(String managerName, String managerPwd, String enCode, HttpSession session){
		//先判断验证码是否正确
		String code=(String)session.getAttribute("code");
		if(code.equalsIgnoreCase(enCode)) {
			// 在web环境中安全管理器会自动进行初始化
			// 获取主体
			Subject subject = SecurityUtils.getSubject();
			try {
				subject.login(new UsernamePasswordToken(managerName,managerPwd));
				session.setAttribute("managerName",managerName);
				return "success";
			} catch (Exception e) {
				e.printStackTrace();
				return "loser";
			}
		}else{
			return "loser";
		}
	}


②  中间经过一系列的包装,方法走到doGetAuthenticationInfo【认证】,验证账号密码是否正确

protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
   //首先强转为UsernamePasswordToken  可以获取到用户名->查询数据库->验证
   UsernamePasswordToken token=(UsernamePasswordToken)authenticationToken;
   String managerName=token.getUsername();
   
   Manager manager=managerService.queryManagerByName(managerName);
   if (manager!=null){
      return new SimpleAuthenticationInfo(managerName,
            manager.getManagerPwd(),
            ByteSource.Util.bytes(manager.getManagerSalt()),
            UUID.randomUUID().toString());
   }
   return null;
}

验证方法返回的SimpleAuthenticationInfo对象的四个参数: 用户名,加密后的密码,加密的盐,无重复的数。【采用哪种加密算法和散列运算的次数在配置文件中配置】  参考application-context-shiro.xml。


验证失败会以异常的形式抛出 【罗列常见的两种异常,我们可以捕获异常给予用户友好的提示。】

UnknownAccountException
账号不存在异常如下:
org.apache.shiro.authc.UnknownAccountException: No account found for user。。。。

IncorrectCredentialsException
当输入密码错误会抛此异常,如下:
org.apache.shiro.authc.IncorrectCredentialsException: Submitted credentials for token [org.apache.shiro.authc.UsernamePasswordToken - zhangsan, rememberMe=false] did not match the expected credentials.


授权的过程  【获取用户名->查询数据库->绑定角色、权限】

提示,只有先认证成功,才会走到授权这一步。

protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
		//获取用户名 【登陆账号】
		String username = (String) principalCollection.getPrimaryPrincipal();
		List<Role> list=managerService.queryRole(username);
                //这里只查询了角色
		if(list!=null){
			SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
			for (Role role : list) {
				info.addRole(role.getRoleName());
			}
			return info;
		}
		return null;
	}


在JSP页面我们一通过Shiro定义的标签轻松判断用户拥有哪些权限和角色,通过标签来控制页面的展示信息。


标签的使用和相关功能【18年7月14日 补充】

//JSP页面引入shiro标签库
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
        <shiro:guest></shiro:guest>//判断用户是否为游客
	<shiro:user></shiro:user>//判断用户是否已经登录(包括已认证和已记住)
	<shiro:hasRole name="root"></shiro:hasRole>//判断用户是否具有某个角色
	<shiro:lacksRole name="root"></shiro:lacksRole>//判断用户是否缺少某个角色
	<shiro:hasAnyRoles name="root,admin"></shiro:hasAnyRoles>>//判断用户是否具有任意某个角色
	<shiro:hasPermission name="user:add"></shiro:hasPermission>//判断用户是否具有某个权限
	<shiro:lacksPermission name="user:add"></shiro:lacksPermission>//判断用户是否缺少某个权限



猜你喜欢

转载自blog.csdn.net/Sugar_map/article/details/81037365