Shiro中自定义Realm的作用(FormAuthenticationFilter和PermissionAuthorizationFilter)以及源码解析
2017-02-15 19:25
1876 查看
在使用shiro时都会自定义一个Realm,Realm的作用就是提供给shiro和数据库进行交互的一个中间层,这样shiro能够帮助我们处理登录(成功、失败),授权,访问控制等功能,但是用户登录的用户信息和用户具体的权限信息是shiro未知的,所以需要每次都请求Realm,由Realm提供
比如授权的流程
使用PermissionAuthorizationFilter
在xml中设置权限
${adminPath}/areaInfo = perms[area:query,area:add]
当发出这个请求(已经验证通过)被PermisssionsAuthorizationFilter拦截,发现需要权限
会调用realm的doGetAuthorizationInfo获取数据库中正确的数据库权限(所以realm的作用 就是查询,剩下的活是shiro的)
PermissionAuthorizationFilter对请求的url对应的权限和从realm中获取的权限进行对比
登录和授权,realm只提供查找返回,不提供逻辑处理,都由shiro解决
拿login来分析
当请求信息是login时,FormAuthenticationFilter会对其进行拦截,解析是不是login请求,并处理
//FormAuthenticationFilter 判断是不是一个login请求
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
if (isLoginRequest(request, response)) {
if (isLoginSubmission(request, response)) {
if (log.isTraceEnabled()) {
log.trace("Login submission detected. Attempting to execute login.");
}
return executeLogin(request, response);
} else {
if (log.isTraceEnabled()) {
log.trace("Login page view.");
}
//allow them to see the login page ;)
return true;
}
} else {
if (log.isTraceEnabled()) {
log.trace("Attempting to access a path which requires authentication. Forwarding to the " +
"Authentication url [" + getLoginUrl() + "]");
}
saveRequestAndRedirectToLogin(request, response);
return false;
}
}可以看到如果是login请求会执行executeLogin方法
//AuthenticatingFilter 此处找到subject.login(token)操作
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);//调用了realm
return onLoginSuccess(token, subject, request, response);
} catch (AuthenticationException e) {
return onLoginFailure(token, e, request, response);
}
}
重点来了
public Subject login(Subject subject, AuthenticationToken token) throws AuthenticationException {
AuthenticationInfo info;
try {
info = authenticate(token);
} catch (AuthenticationException ae) {
try {
onFailedLogin(token, ae, subject);
} catch (Exception e) {
if (log.isInfoEnabled()) {
log.info("onFailedLogin method threw an " +
"exception. Logging and propagating original AuthenticationException.", e);
}
}
throw ae; //propagate
}
Subject loggedIn = createSubject(token, info, subject);
onSuccessfulLogin(token, info, loggedIn);
return loggedIn;
}
我们发现public class DefaultSecurityManager extends SessionsSecurityManager
也就是上面的securityManager的实现类中调用的login,这里就是反悔了一个AuthenticationInfo对象,其中autheticate(token)这个方法继续跟踪到最后就会到达我们的自定义realm中的doGetAuthenticationInfo方法
所以这个info主要是为这行代码服务的
Subject loggedIn = createSubject(token, info, subject);即生成subject的代码
这样就完成了交互
比如授权的流程
使用PermissionAuthorizationFilter
在xml中设置权限
${adminPath}/areaInfo = perms[area:query,area:add]
当发出这个请求(已经验证通过)被PermisssionsAuthorizationFilter拦截,发现需要权限
会调用realm的doGetAuthorizationInfo获取数据库中正确的数据库权限(所以realm的作用 就是查询,剩下的活是shiro的)
PermissionAuthorizationFilter对请求的url对应的权限和从realm中获取的权限进行对比
登录和授权,realm只提供查找返回,不提供逻辑处理,都由shiro解决
拿login来分析
当请求信息是login时,FormAuthenticationFilter会对其进行拦截,解析是不是login请求,并处理
//FormAuthenticationFilter 判断是不是一个login请求
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
if (isLoginRequest(request, response)) {
if (isLoginSubmission(request, response)) {
if (log.isTraceEnabled()) {
log.trace("Login submission detected. Attempting to execute login.");
}
return executeLogin(request, response);
} else {
if (log.isTraceEnabled()) {
log.trace("Login page view.");
}
//allow them to see the login page ;)
return true;
}
} else {
if (log.isTraceEnabled()) {
log.trace("Attempting to access a path which requires authentication. Forwarding to the " +
"Authentication url [" + getLoginUrl() + "]");
}
saveRequestAndRedirectToLogin(request, response);
return false;
}
}可以看到如果是login请求会执行executeLogin方法
//AuthenticatingFilter 此处找到subject.login(token)操作
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);//调用了realm
return onLoginSuccess(token, subject, request, response);
} catch (AuthenticationException e) {
return onLoginFailure(token, e, request, response);
}
}
//DelegatingSubject public void login(AuthenticationToken token) throws AuthenticationException { clearRunAsIdentitiesInternal(); Subject subject = securityManager.login(this, token);//调用了realm PrincipalCollection principals; String host = null; if (subject instanceof DelegatingSubject) { DelegatingSubject delegating = (DelegatingSubject) subject; //we have to do this in case there are assumed identities - we don't want to lose the 'real' principals: principals = delegating.principals; host = delegating.host; } else { principals = subject.getPrincipals(); } if (principals == null || principals.isEmpty()) { String msg = "Principals returned from securityManager.login( token ) returned a null or " + "empty value. This value must be non null and populated with one or more elements."; throw new IllegalStateException(msg); } this.principals = principals; this.authenticated = true; if (token instanceof HostAuthenticationToken) { host = ((HostAuthenticationToken) token).getHost(); } if (host != null) { this.host = host; } Session session = subject.getSession(false); if (session != null) { this.session = decorate(session); } else { this.session = null; } }由securityManager进行登录
重点来了
public Subject login(Subject subject, AuthenticationToken token) throws AuthenticationException {
AuthenticationInfo info;
try {
info = authenticate(token);
} catch (AuthenticationException ae) {
try {
onFailedLogin(token, ae, subject);
} catch (Exception e) {
if (log.isInfoEnabled()) {
log.info("onFailedLogin method threw an " +
"exception. Logging and propagating original AuthenticationException.", e);
}
}
throw ae; //propagate
}
Subject loggedIn = createSubject(token, info, subject);
onSuccessfulLogin(token, info, loggedIn);
return loggedIn;
}
我们发现public class DefaultSecurityManager extends SessionsSecurityManager
也就是上面的securityManager的实现类中调用的login,这里就是反悔了一个AuthenticationInfo对象,其中autheticate(token)这个方法继续跟踪到最后就会到达我们的自定义realm中的doGetAuthenticationInfo方法
所以这个info主要是为这行代码服务的
Subject loggedIn = createSubject(token, info, subject);即生成subject的代码
这样就完成了交互
相关文章推荐
- shiro 自定义FormAuthenticationFilter,记住我
- shiro表单的验证 自定义FormAuthenticationFilter
- Shiro登录机制验证,自定义FormAuthenticationFilter
- shiro- session,自定义FormAuthenticationFilter(表单认证器)-->实现验证码校验
- (四)seajs.config中vars、alias、paths和map的作用,以及util-path路径解析源码
- RedGlovePermission 权限管理系统源码(支持自定义权限、模块,支持角色权限,用户独立权限以及多角色权限)
- shiro.ini配置FormAuthenticationFilter验证、缓存、session、并发限制
- FormAuthenticationFilter与doGetAuthenticationInfo的作用
- 自定义shiro的Realm实现和CredentialsMatcher实现以及Token实现
- ViewDragHelper完全解析以及对自定义ViewGroup的作用
- (十)shiro之自定义Realm以及自定义Realm在web的应用demo
- Spring-shiro源码陶冶-AuthorizingRealm用户认证以及授权
- RedGlovePermission 权限管理系统源码(支持自定义权限、模块,支持角色权限,用户独立权限以及多角色权限)
- Shiro的FormAuthenticationFilter登陆成功不跳转
- spring boot 源码解析31-AuthenticationAuditListener,AuthorizationAuditListener
- shiro试用记录-FormAuthenticationFilter
- Shiro FormAuthenticationFilter
- (四)自定义多个Realm以及Authenticator与AuthenticationStrategy
- Shiro - 自定义filterChainDefinitions和Realm
- xmlns:android作用以及自定义布局属性