Shiro笔记一:shiro认证、与Web集成、工作流程、DelegatingFilterProxy、URL匹配顺序、认证思路与实现、Realm、Shiro密码的比对

  1. Shiro_简介

http://jinnianshilongnian.iteye.com/blog/2018936

 

 

3. Shiro_Web集成

Shiro 提供了与 Web 集成的支持,其通过一个
ShiroFilter 入口来拦截需要安全控制的URL,然后
进行相应的控制
ShiroFilter 类似于如 Strut2/SpringMVC 这种
web 框架的前端控制器,是安全控制的入口点,其
负责读取配置(如ini 配置文件),然后判断URL
是否需要登录/权限等工作

 

1首先在web.xml中的配置spring以及springMvc,和shiroFilter属性。

2.然后配置好springMvc的配置文件spirng-servlet.xml文件。

3.applicationContext.xml配置spring中shiro的配置,一些主要的组件。

 

4. Shiro_大致的工作流程

首先Web.xml中配置的shiroFilter作为入口 拦截所有资源 ,

Shiro笔记一:shiro认证、与Web集成、工作流程、DelegatingFilterProxy、URL匹配顺序、认证思路与实现、Realm、Shiro密码的比对_第1张图片

 

哪些页面可以访问?

有两种,一种是在applicationContext的filterChain中配置的过滤器是匿名的。另外一种就是里面没有配置的也可以访问。否则都会被重定向到login的页面。

 

5. Shiro_DelegatingFilterProxy

DelegatingFilterProxy 作用是自动到 Spring 容器查找名字为 shiroFilter( filter-name) 的 bean 并把所有 Filter的操作委托给它。所以applicationContxt中的id必须要和web.xml文件中的一致。

 

 

一、shiro认证

6. Shiro_权限 URL 配置细节

Shiro笔记一:shiro认证、与Web集成、工作流程、DelegatingFilterProxy、URL匹配顺序、认证思路与实现、Realm、Shiro密码的比对_第2张图片

 

Shiro笔记一:shiro认证、与Web集成、工作流程、DelegatingFilterProxy、URL匹配顺序、认证思路与实现、Realm、Shiro密码的比对_第3张图片

比如下图:配置了list.jsp可以anon匿名访问,但是前面有个/**的所有页面需要认证后才能访问第一次匹配了list.jsp所以就不能访问到了。

Shiro笔记一:shiro认证、与Web集成、工作流程、DelegatingFilterProxy、URL匹配顺序、认证思路与实现、Realm、Shiro密码的比对_第4张图片

7. Shiro_认证思路分析

Shiro笔记一:shiro认证、与Web集成、工作流程、DelegatingFilterProxy、URL匹配顺序、认证思路与实现、Realm、Shiro密码的比对_第5张图片

对login()方法疯狂进入,底层就会发现认证最终是通过继承的AuthenticatingRealm类中的doGetAuthenticationInfo()方法。

 

8. Shiro_实现认证流程

1. Controller表现层中接收到传递过来的username和password的表单数据,封装为UsernamePasswordToken的token对象,然后执行Subject.login(token)方法。实现将token对象传入到Realm的doGetAuthticationInfo(AuthticationToken token)方法中,此观点可以通过打印表现层和Realm层的token的hashCode值来验证。

 

9. Shiro_实现认证 Realm

public class ShiroRealm extends AuthorizingRealm {

   @Override

   protected AuthenticationInfo doGetAuthenticationInfo(

         AuthenticationToken token) throws AuthenticationException {

      System.out.println("[FirstRealm] doGetAuthenticationInfo");

      //1. 把 AuthenticationToken 转换为 UsernamePasswordToken 

      UsernamePasswordToken upToken = (UsernamePasswordToken) token;

      //2. 从 UsernamePasswordToken 中来获取 username

      String username = upToken.getUsername();

      //3. 调用数据库的方法, 从数据库中查询 username 对应的用户记录

      System.out.println("从数据库中获取 username: " + username + " 所对应的用户信息.");

      

      //4. 若用户不存在, 则可以抛出 UnknownAccountException 异常

      if("unknown".equals(username)){

         throw new UnknownAccountException("用户不存在!");

      }

      //5. 根据用户信息的情况, 决定是否需要抛出其他的 AuthenticationException 异常. 

      if("monster".equals(username)){

         throw new LockedAccountException("用户被锁定");

      }

      //6. 根据用户的情况, 来构建 AuthenticationInfo 对象并返回. 通常使用的实现类为: SimpleAuthenticationInfo

      //以下信息是从数据库中获取的.

      //1). principal: 认证的实体信息. 可以是 username, 也可以是数据表对应的用户的实体类对象. 

      Object principal = username;

      //2). credentials: 数据库查询到的密码. 

      Object credentials = null; //"fc1709d0a95a6be30bc5926fdb7f22f4";

      if("admin".equals(username)){

         credentials = "038bdaf98f2037b31f1e75b5b4c9b26e";

      }else if("user".equals(username)){

         credentials = "098d2c478e9c11555ce2823231e02ec1";

      }

      //3). realmName: 当前 realm 对象的 name. 调用父类的 getName() 方法即可

      String realmName = getName();

      //4). 盐值. 

      ByteSource credentialsSalt = ByteSource.Util.bytes(username);

      SimpleAuthenticationInfo info = null; //new SimpleAuthenticationInfo(principal, credentials, realmName);

      info = new SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName);
      return info;

   }

 

注意:测试中登录信息成功后会被shiro缓存,所以需要是用登出过滤器来进行清除缓存,不然会使用到缓存导致测试的结果不正确。登出过滤器logout

 
 

    

    

        

            /login.jsp = anon

            /shiro/login = anon

            /shiro/logout = logout

            /user.jsp = roles[user]

            /admin.jsp = roles[admin]

            # everything else requires authentication:

            /** = authc

        

    

密码的比对过程是有shiro来给我们完成的,下面详细解释。

 

10. Shiro_密码的比对

在Realm的doGetAuthticationInfo()方法中已经有了表现层传过来的UsernamePasswordToken对象和SimpleAuthticationInfo对象,这两个对象中分别保存着前台和数据库中查询出来的username、password。

 

这个比对过程必定是通过两个对象的获得密码方法得到密码后进行的, 所以在UsernamePasswordToken类中getPassword()方法中打个断点,debug进入该断点后,通过debug界面向下查找到前几步执行的方法就很容易发现,是通过CredentialsMatcher来进行比较的。

 

下面讲如何使用MD5盐值加密。Credentials的。

你可能感兴趣的:(Shiro)