shiro权限认证及授权的执行流程分析及图解

(配置文件请看下一个博客)

https://blog.csdn.net/weixin_41716049/article/details/84336669

https://blog.csdn.net/weixin_41716049/article/details/84336696

为了颜色标识注释,前面没有使用代码框,多多担待

《一,认证》

1.先建两个class文件

   一个写 AuthRealm (授权与认证方法,并继承) extends AuthorizingRealm  

获取其默认方法doGetAuthorizationInfo(授权方法) doGetAuthenticationInfo(认证方法) 

                 一个写PasswordMatcher(密码验证器,并继承) extends SimpleCredentialsMatcher

获取默认方法doCredentialsMatch 

2.在Action的登录方法中 

         @Action("loginAction_login")//重页面跳转过来的路径名

         public String login() throws Exception {

             //判断用户名是不是为空,如果是说明没有登录,跳转到用户登录页面

             if(UtilFuns.isEmpty(username)){

                    return "login";

             }

//1.SecurityUtils:是shiro的一个工具类。通过SecurityUtils获取getSubject 得到一个返回值

             Subject subject = SecurityUtils.getSubject();

//3.根据逻辑2。new一个 UsernamePasswordToken,并传上用户名及密码。把返回值传给登入作为条件。

             UsernamePasswordToken token = new UsernamePasswordToken(username,password);

             

             try {

//2. subject的返回值里有两个方法logout:登出 login:登入。这里我们使用登录方法,通过方法我们可以看到需要一个返回值:AuthenticationToken的类型,又因为AuthenticationToken  是一个接口,所以我们使用他下面的UsernamePasswordToken 的实现类来写(ps:查看方法:Ctrl+t),

                    subject.login(token);//当调用subject的登入方法时,会跳转到认证的方法上。。。。。。。。。。

 

//4.在证方法中subject已经把获取到了用户,所以我们用subject.getPrincipal 可以获取到登录的用户,Principal:他是在认证方法中的principal:主要对象(登录的用户,详情看认证方法return的哪一步注释)

                    User user = (User) subject.getPrincipal();

//5.把user用户数据通过Session.put放在session值栈中。SysConstant.CURRENT_USER_INFO:是一个返回的值,在jsp页面中可以接收到,也可以直接写一个字符串让页面接收,返回的数据可以在页面做回显等功能

                    session.put(SysConstant.CURRENT_USER_INFO, user);

                    return SUCCESS;//以上全部都过了后,让其访问页面数据

             } catch (Exception e) {

                    // TODO Auto-generated catch block

                    e.printStackTrace();

                    super.put("errorInfo", "您的用户名或密码错误"); //登录页面的错误信息提示

                    return "login";

             }

       }

       

       

       //退出

       @Action("loginAction_logout")

       public String logout(){

             session.remove(SysConstant.CURRENT_USER_INFO);       //删除session

             SecurityUtils.getSubject().logout();   //调用登出方法

             return "logout";

       }

3.在认证方法中的doGetAuthenticationInfo

            protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {

             // TODO Auto-generated method stub

             System.out.println("调用认证方法");

             UsernamePasswordToken token =(UsernamePasswordToken)arg0;//先将arg0强转为UsernamePasswordToken类型

             final String username = token.getUsername();//通过token获取到用户名

             Specification<User> spec = new Specification<User>() {   //把username 设为查询条件,查询数据库是否有这个用户名

                    @Override

                    public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {

                           // TODO Auto-generated method stub

                           return cb.equal(root.get("username").as(String.class),username);

                    }

             };

             List<User> find = userServiceimpl.find(spec); //把spec 条件放到 查询中查询数据  查询用户名

             if(find!=null&& find.size()>0){  //判断返回的结果不为空,及返回的数不小于0

                    User user = find.get(0); //通过索引获取到返回值的第一个数中的数据

                    return new SimpleAuthenticationInfo(user, user.getPassword(), getName()) ;//这里如果上面的都成立后会return到密码校验哪里去

  /*   SimpleAuthenticationInfo:是doGetAuthenticationInfo的一个实现类,因为doGetAuthenticationInfo 是一个接口不能直接new  

       把返回值添加到条件中 //principal:主要对象(登录的用户) , credentials:密码 ,realm的名字可以通过getName获取类名作为区分 */

             }

             return null;

       }

 

4.在密码检验中PasswordMatcher  

public class PasswordMatcher extends SimpleCredentialsMatcher {  //先实现一个接口SimpleCredentialsMatcher  获取doCredentialsMatch的内部方法

       @Override

       public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {

             

             System.out.println("调用了密码对比器");

             UsernamePasswordToken utoken = (UsernamePasswordToken) token; 

           /*[把AuthenticationToken 中的token 装换为AuthenticationToken 中的(ps:查看方法Ctrl+t)

           UsernamePasswordToken实现类 因为AuthenticationToken 是接口不能new数据],*/

             

             String pwd = new String(utoken.getPassword());//通过utoken 获取用户密码,并转换成String类型,注意这里的转换不能强转,要用new的方法

             //source:要加密的内容   salt:增加复杂度的内容  哈希次数:2

             Md5Hash md5Hash = new Md5Hash(pwd, utoken.getUsername(), 2);  //调用Md5加密 为输入的数据加密

             String credentials = (String)info.getCredentials();  //通过AuthenticationInfo 的info 查询数据库的密码 装换成String类型

             return equals(md5Hash.toString(),credentials); //对比用户输入的数据和数据库密码是否一致。return走,返回到Action方法中。

       }

}

 

5.执行流程图解

 

 

 

《二,授权》

1.在授权方法中

 
  1. protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {

  2.  
  3.         System.out.println("进入授权方法");

  4.  
  5.     SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

  6.  
  7.         

  8.  
  9.         User user = (User) arg0.getPrimaryPrincipal();

  10.  
  11.         //获取用户的角色及角色的模块

  12.  
  13.         Set<Role> roles = user.getRoles();  //通过用户查到用户角色

  14.  
  15.         for (Role role : roles) {//遍历数据

  16.  
  17.             Set<Module> modules = role.getModules();//通过用户查到用户模块

  18.  
  19.             for (Module module : modules) {

  20.  
  21.                 info.addStringPermission(module.getCpermission());

  22. //通过用户模块查到模块名并添加到info中。也就是说把查到的模块显示到页面中,没有的就代表没授权

  23.  
  24.             }

  25.  
  26.         }

  27.  
  28.         return info;  //返回到jsp页面中

  29.  
  30.     }

 

2.jsp页面

 
  1.  <%@ taglib uri="http://shiro.apache.org/tags" prefix="shiro" %>

  2.  
  3.  //要想使用shiro的标签就一点要导数据标签

  4.  
  5.  
  6.  
  7. <shiro:hasPermission name="部门管理"> //shiro:hasPermission:拥有权限的资源  name:权限访问的名字,如上:当该用户里有部门管理权限时,才会让其看到部门管理这个按钮

  8.  
  9.             <li><a href="${ctx}/sysadmin/deptAction_list" onclick="linkHighlighted(this)" target="main" id="aa_1">部门管理</a></li>

  10.  
  11. </shiro:hasPermission>

3.以上方法可以使用户看不到自己没有权限的数据,但是如果用户自己写链接还是能访问到数据的,

解决方法一(推荐):过滤器链的权限配置方式:

 
  1. <value>

  2.  
  3.                 /index.jsp* = anon

  4.  
  5.                 /home* = anon

  6.  
  7.                 /sysadmin/login/login.jsp* = anon

  8.  
  9.                 /sysadmin/login/loginAction_logout* = anon

  10.  
  11.                 /login* = anon

  12.  
  13.                 /logout* = anon

  14.  
  15.                 /components/** = anon

  16.  
  17.                 /css/** = anon

  18.  
  19.                 /img/** = anon

  20.  
  21.                 /js/** = anon

  22.  
  23.                 /plugins/** = anon

  24.  
  25.                 /images/** = anon

  26.  
  27.                 /js/** = anon

  28.  
  29.                 /make/** = anon

  30.  
  31.                 /skin/** = anon

  32.  
  33.                 /stat/** = anon

  34.  
  35.                 /ufiles/** = anon

  36.  
  37.                 /validator/** = anon

  38.  
  39.                 /resource/** = anon

  40.  
  41.                  //在这里进行配置,下面的以上为 /sysadmin/deptAction_*路径下的所有方法都必须要有部门管理权限才可以进入访问,(ps:在写方法时,建议写一个在这里就配置一个,避免混淆了)

  42.  
  43.                 /sysadmin/deptAction_* = perms["部门管理"]

  44.  
  45.                 /** = authc

  46.  
  47.                 /*.* = authc

  48.  
  49.             </value>

解决方法二(推荐):注解的方式:

 
  1. //这里代表的时要走这个方法模块中就得有角色管理这个模块,没有就拒绝访问

  2.  
  3. @RequiresPermissions(value="角色管理")

  4.  
  5.     public Page<Role> findPage(Specification<Role> spec, Pageable pageable) {

  6.  
  7.         // TODO Auto-generated method stub

  8.  
  9.         return roleDao.findAll(spec, pageable);

  10.  
  11.     }

shiro:的配置

1.导包:shiro.All 1.2.3 

2.配置过滤器:在web.xml中 ,注意这段过滤器要写在struts2的过滤器前面。


   

 
  1.   <filter>

  2.  
  3.              <filter-name>shiroFilter</filter-name>

  4.  
  5.               <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>

  6.  
  7.              <init-param>

  8.  
  9.                     <param-name>targetFilterLifecycle</param-name>

  10.  
  11.                     <param-value>true</param-value>

  12.  
  13.              </init-param>

  14.  
  15.        </filter>

  16.  
  17.        <filter-mapping>

  18.  
  19.              <filter-name>shiroFilter</filter-name>

  20.  
  21.              <url-pattern>/*</url-pattern>

  22.  
  23.        </filter-mapping>

 

3.   <!-- 在applicationContext.xml中告诉spring生成shiro代理子类时,采用cglib方式生成 -->

    <aop:aspectj-autoproxy proxy-target-class="true" /> 

4.写shiro的配置文件:applicationContext-shiro


 

 
  1. <?xml version="1.0" encoding="UTF-8"?>

  2.  
  3. <beans xmlns="http://www.springframework.org/schema/beans"

  4.  
  5.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"

  6.  
  7.     xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"

  8.  
  9.     xmlns:aop="http://www.springframework.org/schema/aop"

  10.  
  11.     xsi:schemaLocation="http://www.springframework.org/schema/beans

  12.  
  13. http://www.springframework.org/schema/beans/spring-beans.xsd

  14.  
  15. http://www.springframework.org/schema/aop

  16.  
  17. http://www.springframework.org/schema/aop/spring-aop.xsd

  18.  
  19. http://www.springframework.org/schema/tx

  20.  
  21. http://www.springframework.org/schema/tx/spring-tx.xsd

  22.  
  23. http://www.springframework.org/schema/context

  24.  
  25. http://www.springframework.org/schema/context/spring-context.xsd">

  26.  
  27.  
  28.  
  29.     <!-- 配置Spring整合shiro -->

  30.  
  31.  
  32.     <!-- 密码比较器类 -->

  33.  
  34.     <bean id="passwordMatcher" class="cn.itcast.web.action.shiro.PasswordMatcher" />

  35.  
  36.  
  37.     <!-- 编写realm类 -->

  38.  
  39.     <bean id="authRealm" class="cn.itcast.web.action.shiro.AuthRealm">

  40.  
  41.         <!-- 注入密码比较器对象 -->

  42.  
  43.         <property name="credentialsMatcher" ref="passwordMatcher" />

  44.  
  45.     </bean>

  46.  
  47.  
  48.     <!-- 配置安全管理器 -->

  49.  
  50.     <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">

  51.  
  52.         <!-- 自己编写一个realm域对象 -->

  53.  
  54.         <property name="realm" ref="authRealm" />

  55.  
  56.     </bean>

  57.  
  58.  
  59.  
  60.     <!-- Spring框架需要整合shiro安全框架 -->

  61.  
  62.     <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">

  63.  
  64.         <!-- 注入安全管理器 -->

  65.  
  66.         <property name="securityManager" ref="securityManager" />

  67.  
  68.         <!-- 登录页面 -->

  69.  
  70.         <property name="loginUrl" value="/index.jsp" />

  71.  
  72.         <!-- 认证成功了,跳转的页面 <property name="successUrl" value=""/> -->

  73.  
  74.         <!-- 没有权限的跳转页面 -->

  75.  
  76.         <property name="unauthorizedUrl" value="/index2.jsp" />

  77.  
  78.         <!-- 定义访问的规则 -->

  79.  
  80.         <property name="filterChainDefinitions">

  81.  
  82.             <!-- /**代表下面的多级目录也过滤     注意:下面的过滤一定要遵循从小到大原则 ,并且不要写标点符号在后方,每条数据单独写一行,不要换行,尽量不要使用自动调整格式,会造成格式错误。

  83.  
  84. anon, authc :权限拦截器 ,anon:代表可以访问的路径,authc :代表不可以访问的路径。

  85.  
  86.         -->

  87.  
  88.             <value>

  89.  
  90.                 /index.jsp* = anon

  91.  
  92.                 /home* = anon

  93.  
  94.                 /sysadmin/login/login.jsp* = anon

  95.  
  96.                 /sysadmin/login/loginAction_logout* = anon

  97.  
  98.                 /login* = anon

  99.  
  100.                 /logout* = anon

  101.  
  102.                 /components/** = anon

  103.  
  104.                 /css/** = anon

  105.  
  106.                 /img/** = anon

  107.  
  108.                 /js/** = anon

  109.  
  110.                 /plugins/** = anon

  111.  
  112.                 /images/** = anon

  113.  
  114.                 /js/** = anon

  115.  
  116.                 /make/** = anon

  117.  
  118.                 /skin/** = anon

  119.  
  120.                 /stat/** = anon

  121.  
  122.                 /ufiles/** = anon

  123.  
  124.                 /validator/** = anon

  125.  
  126.                 /resource/** = anon

  127.  
  128.                 /** = authc

  129.  
  130.                 /*.* = authc

  131.  
  132.             </value>

  133.  
  134.         </property>

  135.  
  136.     </bean>

  137.  
  138.  
  139.  
  140.     <!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->

  141.  
  142.     <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />

  143.  
  144.  
  145.  
  146.     <!-- 生成代理,通过代理进行控制 -->

  147.  
  148.     <bean

  149.  
  150.         class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"

  151.  
  152.         depends-on="lifecycleBeanPostProcessor">

  153.  
  154.         <property name="proxyTargetClass" value="true" />

  155.  
  156.     </bean>

  157.  
  158.  
  159.     <!-- 安全管理器 -->

  160.  
  161.     <bean

  162.  
  163.         class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">

  164.  
  165.         <property name="securityManager" ref="securityManager" />

  166.  
  167.     </bean>

  168.  
  169. </beans>

  170.  

 

 

5. 在applicationContext.xml 中加载shiro文件

<import resource="classpath:applicationContext-shiro.xml"/>

----------------------------------------------------------------------------------

二 shiro的使用方法流程。

1.shiro执行流程图解:

2.shiro登录的过程图解:

 

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值