<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean" >
<property name="securityManager" ref="securityManager" />
<property name="loginUrl" value = "/login" />
<property name="successUrl" value = "/" />
<property name="unauthorizedUrl" value = "/unauthorize"/>
<property name="filterChainDefinitions">
<value>
/static/**=anon
/login=authc
/logout=logout
/unauthorize=authc
/**=user,perms
</value>
</property>
</bean>
由於shiro默認註冊了FormAuthenticationFilter,所以配置中可以不需要爲此方法定義bean,但有個前提,登錄頁面中的登錄賬號和密碼,記住我的name必須和FormAuthenticationFilter默認的名稱一致,如下圖
<bean id="formAuthenticationFilter" class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter">
<property name="usernameParam" value="name"/>
<property name="passwordParam" value="password1"/>
<property name="rememberMeParam" value="rememberMe1"/>
<property name="loginUrl" value="/login"/>
<property name="successUrl" value="/"/>
</bean>
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean" >
<property name="securityManager" ref="securityManager" />
<property name="loginUrl" value = "/login" />
<property name="successUrl" value = "/" />
<property name="unauthorizedUrl" value = "/unauthorize"/>
<property name="filters">
<map>
<entry key="authc" value-ref="formAuthenticationFilter"/>
</map>
</property>
<property name="filterChainDefinitions">
<value>
/static/**=anon
/login=authc
/logout=logout
/unauthorize=authc
/**=user,perms <
</value>
</property>
</bean>
登錄頁面提交後,跳轉到 /login,進入登錄方法,由於此路徑權限設置爲authc,shiro對該路徑進行過濾,authc權限由FormAuthenticationFilter進行過濾。登錄請求進入onAccessDenied方法protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
if (isLoginRequest(request, response)) { //判斷是否是登錄請求
if (isLoginSubmission(request, response)) { // 是否是http post請求
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;
}
}
其中 executeLogin(request, response)方法的具體實現在繼承的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);
}
}
剖析:createToken(request, response); 具體實現在子類FormAuthenticationFilter中
protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
String username = getUsername(request);
String password = getPassword(request);
return createToken(username, password, request, response);
}
@RequestMapping(value = "/login") public String toLogin(HttpServletRequest request, Model model){ String exceptionClassName = (String)request.getAttribute("shiroLoginFailure"); String error = null; if(UnknownAccountException.class.getName().equals(exceptionClassName)) { error = "用戶名/密碼錯誤"; } else if(IncorrectCredentialsException.class.getName().equals(exceptionClassName)) { error = "用戶名/密碼錯誤"; } else if(exceptionClassName != null) { error = "其他錯誤:" + exceptionClassName; } model.addAttribute("error", error); return "login"; // 跳轉到登錄頁面 }
UsernamePasswordToken token = new UsernamePasswordToken(userName, password);
try {
subject.login(token);
} catch (UnknownAccountException ua){
returnInfo.setMessage("用戶名錯誤");
} catch (IncorrectCredentialsException ic){
returnInfo.setMessage("密碼錯誤");
}
}
anon(AnonymousFilter.class),
authc(FormAuthenticationFilter.class),
authcBasic(BasicHttpAuthenticationFilter.class),
logout(LogoutFilter.class),
noSessionCreation(NoSessionCreationFilter.class),
perms(PermissionsAuthorizationFilter.class),
port(PortFilter.class),
rest(HttpMethodPermissionFilter.class),
roles(RolesAuthorizationFilter.class),
ssl(SslFilter.class),
user(UserFilter.class);
}
IncorrectCredentialsException(密碼錯誤)
DisabledAccountException(帳號被禁用)
LockedAccountException(帳號被鎖定)
ExcessiveAttemptsException(登錄失敗次數過多)
ExpiredCredentialsException(憑證過期)等