shiro整体流程

开始全流程分析:

当访问对应的url 的时候,会有对应的过滤器 执行过滤,
比如FormAuthenticationFilter 这个类继承了AuthenticatingFilter 抽象类,

抽象类里有一个方法 :

protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
AuthenticationToken token = createToken(request, response);
if (token == null) {
String msg = "createToken method implementation returned null. A valid non-null AuthenticationToken " +
“must be created in order to execute a login attempt.”;
throw new IllegalStateException(msg);
}
try {
Subject subject = getSubject(request, response);
subject.login(token);
return onLoginSuccess(token, subject, request, response);
} catch (AuthenticationException e) {
return onLoginFailure(token, e, request, response);
}
}

当 需要FormAuthenticationFilter 这个过滤器进行 认证或者权限过滤时候,就会首先走到这个方法内,创建 token,然后 获取subject 执行login方法,如代码所示,如果 成功了,会执行 FormAuthenticationFilter 类的onloginSuccess 方法,失败执行onLoginFailure 方法。

每次请求一个新的需要认证的 url 的时候,就需要走到这方法,进行过滤。

举例说明 :访问/login 方法 会被进行过滤,onloginSuccess 方法里会再重定向到/login 方法执行。

protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
//登录成功后,从session中去除校验码
Session session = subject.getSession();
session.removeAttribute(CAPTCHA_SESSION);

   //触发执行鉴权方法
   SecurityManager.isSessionUserAdminRole();

if (redirectToSavedRequest) {
return super.onLoginSuccess(token, subject, request, response);
} else {
WebUtils.issueRedirect(request, response, getSuccessUrl());
return false;
}
}

另一种实现认证方式:

也可以不配置/login =authc

而是在/login 对应的控制器方法内,创建token 并执行

Subject subject = getSubject(request, response);
subject.login(token);
然后在执行 subject.isAuthenticated()进行判断 。
两种方式都可以实现,但是推荐使用第一种。因为配置简单。没有代码侵入。第二种容易理解。 但是笔者在这里强烈建议采取第一种方式,开发肯定要避免逻辑相同的代码,同一个登录如果一段代码如果每次登录都需要执行,那么开销太大了
subject.login(token); 执行内部逻辑

接下来我们进入login方法 看看内部是怎样实现的.代码如下,(截取了一部分)
在这里插入图片描述
进入securityManager的login方法 代码如下:
在这里插入图片描述
注意, 这里才开始真正的认证操作, 在这个方法中定义了AuthenticationInfo对象用来接收从Realm传来的认证信息,

进入authenticate方法:

在这里插入图片描述

进入authenticator的authenticate方法,

在这里插入图片描述

发现这是一个抽象类, 在它的authenticate方法中又调用了自己的doAuthenticate方法, 但该类中对doAuthenticate并没有具体实现,所以继续往下走, 看看哪个类对它进行了实现,

进入doAuthenticate方法,(该方法的实现比较长,不使用截图的方式,直接上代码)

ModularRealmAuthenticator:

protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
this.assertRealmsConfigured();
Collection realms = this.getRealms();
return realms.size() == 1?this.doSingleRealmAuthentication((Realm)realms.iterator().next(), authenticationToken):this.doMultiRealmAuthentication(realms, authenticationToken);
}

这才是之前的那个authenticator的真正实现,它的assertRealmsConfigured方法是判断Realm是否存在,不存在则会抛出IllegalStateException.随后根据Realm的个数来判断执行哪个方法,我只配了一个Realm,故会执doSingleRealmAuthentication,并将realm和token作为参数传入, 当然, 传入的realm实际上就是我自定义的ShiroRealm.

● 进入doSingleRealmAuthentication方法:

在这里插入图片描述

首先判断该realm是否支持认证该token, 显然是支持的,所以执行else,

● 执行了realm的getAuthenticationInfo(token)方法:

在这里插入图片描述
可以看到, 执行了ShiroRealm所继承类的getAuthenticationInfo方法: 首先shiro会先从缓存中获取认证信息(对应getCachedAUthenticationInfo方法),如果没有才会继续从Realm中获取, 因为我们是第一次登录,所以缓存中肯定没有认证信息,所以会执行if语句中的代码

● 注意,这里是重点, 执行了doGetAuthenticationInfo方法

在这里插入图片描述
执行图中箭头指向的方法, 这个方法就是进行密码匹配的

● 进入assertCredentialsMatch(token, info)方法

在这里插入图片描述
该方法首先获取了一个CredentialsMatcher, 译为凭证匹配器, 这里获取的是HashedCredentialsMatcher类的对象(见配置文件),该类的作用是将用户输入的密码以某种算法加密(为了安全考虑,数据库中用户的密码都是以密文保存的).所以需要加密后再对比

● 进入doCredentialsMatch(token, info)

在这里插入图片描述
对token中的password加密后,执行equals方法进行对比,如果相同则认证成功,返回true.反之认证失败, 返回false,并在接下来抛出AuthenticationException. 到此,认证过程结束, 将info原路返回到DefaultSecurityManager.

授权filter 和认证filter 原理差不多,用RolesAuthorizationFilter 做例子:
public class RolesAuthorizationFilter extends AuthorizationFilter {

//TODO - complete JavaDoc

@SuppressWarnings({"unchecked"})
public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {

    Subject subject = getSubject(request, response);
    String[] rolesArray = (String[]) mappedValue;

    if (rolesArray == null || rolesArray.length == 0) {
        //no roles specified, so nothing to check - allow access.
        return true;
    }

    Set<String> roles = CollectionUtils.asSet(rolesArray);
    return subject.hasAllRoles(roles);
}

}

在配置文件中配置了 role[sad] 后,会调用到
isAccessAllowed方法,可以看到 把sad 角色转化进去了,然后判断当前用户是否拥有这个角色。
执行 hasAllRoles 最后会调用
AuthorizingRealm 进行授权判断,并返回授权结果。 当然也可以配置多个realm.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值