<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("密码错误");
}
}
public enum DefaultFilter {
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);
}
UnknownAccountException(账号不存在)
IncorrectCredentialsException(密码错误)
DisabledAccountException(帐号被禁用)
LockedAccountException(帐号被锁定)
ExcessiveAttemptsException(登录失败次数过多)
ExpiredCredentialsException(凭证过期)等