正常情况下,如果我们只是简单的用户名,密码登录,则我们做认证 只要配置默认认证过滤器就好了,
如下:
1 配置文件配置登录认证
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager"/> <property name="loginUrl" value="http://casserver/login?service=http://casclient/shiro-cas"/> <property name="successUrl" value="/welcome.do"/> <property name="unauthorizedUrl" value="/403.do"/> <property name="filterChainDefinitions"> <value> /logout.do*=anon /casticketerror.do*=anon # 权限配置示例 /security/account/view.do=authc,perms[SECURITY_ACCOUNT_VIEW] /** = authc </value> </property> </bean>
如下配置中没有自己定义shiro 过滤器,所以 都是默认过滤器,比如:
Shiro内置的FilterChain
Filter Name | Class |
anon | org.apache.shiro.web.filter.authc.AnonymousFilter |
authc | org.apache.shiro.web.filter.authc.FormAuthenticationFilter |
authcBasic | org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter |
perms | org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter |
port | org.apache.shiro.web.filter.authz.PortFilter |
rest | org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter |
roles | org.apache.shiro.web.filter.authz.RolesAuthorizationFilter |
ssl | org.apache.shiro.web.filter.authz.SslFilter |
user | org.apache.shiro.web.filter.authc.UserFilter |
当访问对应的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); 执行内部逻辑 会走到AuthorizingRealm 进行认证,并返回认证结果。 当然也可以配置多个realm.
授权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.