用了shiro一段时间了,但是有点受不了它请求登录如果验证不通过直接跳的是loginUrl…所以我想很多人想用ajax实现shiro的登录直接在回调函数里面通过js显示出错信息吧。
今天查了一天的资料,结合了别人写的文章,自己也写了这个博客。好了,直接进入主题吧~
首先我们知道shiro主要是通过过滤器来实现权限的验证的,你可以继承各种各样的filter来进行扩展。这里我们实现ajax是通过继承FormAuthenticationFilter来的。下面这个类实现了如果是ajax请求则直接处理登录之后直接将信息通过response返回给客户端,如果是其它请求则直接用的源代码执行下去的,只是把源代码copy到重写的方法里面的而已。具体的可以看源码就会清楚的哦~如下:
package com.sh.ddyc.shiro.filter;
import com.sh.ddyc.constant.Constant;
import com.sh.ddyc.data.mapper.DUserMapper;
import com.sh.ddyc.dto.UserDto;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
public class ExtendFormAuthenticationFilter extends FormAuthenticationFilter {
private static final Logger log = LoggerFactory.getLogger(FormAuthenticationFilter.class);
@Autowired
DUserMapper userMapper;
/**
* 表示当访问拒绝时
* @param request
* @param response
* @return
* @throws Exception
*/
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
if(this.isLoginRequest(request, response)) {
if(this.isLoginSubmission(request, response)) {
if(log.isTraceEnabled()) {
log.trace("Login submission detected. Attempting to execute login.");
}
return this.executeLogin(request, response);
} else {
if(log.isTraceEnabled()) {
log.trace("Login page view.");
}
return true;
}
} else {
if(log.isTraceEnabled()) {
log.trace("Attempting to access a path which requires authentication. Forwarding to the Authentication url [" + this.getLoginUrl() + "]");
}
this.saveRequestAndRedirectToLogin(request, response);
return false;
}
}
/**
* 当登录成功
* @param token
* @param subject
* @param request
* @param response
* @return
* @throws Exception
*/
@Override
protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
//将user对象放入session,这里你可能用不到,可以删除
Map params = new HashMap();
params.put("username",token.getPrincipal().toString());
UserDto userDto = userMapper.findUserDto(params);
//----------以上代码你可以删除-------------------
((HttpServletRequest)request).getSession().setAttribute(Constant.CURRENT_USER,userDto);
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
if (!"XMLHttpRequest".equalsIgnoreCase(httpServletRequest
.getHeader("X-Requested-With"))) {// 不是ajax请求
issueSuccessRedirect(request, response);
} else {
httpServletResponse.setCharacterEncoding("UTF-8");
PrintWriter out = httpServletResponse.getWriter();
out.println("{\"success\":true,\"message\":\"登入成功\"}");
out.flush();
out.close();
}
return false;
}
/**
* 当登录失败
* @param token
* @param e
* @param request
* @param response
* @return
*/
@Override
protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
if (!"XMLHttpRequest".equalsIgnoreCase(((HttpServletRequest) request)
.getHeader("X-Requested-With"))) {// 不是ajax请求
setFailureAttribute(request, e);
return true;
}
try {
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
String message = e.getClass().getSimpleName();
if ("IncorrectCredentialsException".equals(message)) {
out.println("{\"success\":false,\"message\":\"密码错误\"}");
} else if ("UnknownAccountException".equals(message)) {
out.println("{\"success\":false,\"message\":\"账号不存在\"}");
} else if ("LockedAccountException".equals(message)) {
out.println("{\"success\":false,\"message\":\"账号被锁定\"}");
} else {
out.println("{\"success\":false,\"message\":\"未知错误\"}");
}
out.flush();
out.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
return false;
}
}
上面这个类的onAccessDenied()方法表示当访问拒绝时是否已经处理了;如果返回true表示需要继续处理;如果返回false表示该拦截器实例已经处理了,将直接返回即可。onLoginSuccess()方法是登录成功时调用。onLoginFailure()方法是登录失败时调用。
下面是onAccessDenied()方法里面的this.executeLogin(request, response);
这行代码的源码:
可以看出这个方法执行了subject的login()方法登录然后如果登录成功则调用的onLoginSuccess(),如果报错则调用的onLoginFailure()。
好啦,关键的部分讲完了,接下来就是xml的配置了。
喽~
<bean id="formAuthenticationFilter" class="com.sh.ddyc.shiro.filter.ExtendFormAuthenticationFilter">
<property name="usernameParam" value="username"/>
<property name="passwordParam" value="password"/>
<property name="rememberMeParam" value="rememberMe"/>
<property name="loginUrl" value="/login"/>
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="/index" />
<property name="filters">
<util:map>
<entry key="authc" value-ref="formAuthenticationFilter"/>
<entry key="kickout" value-ref="kickoutSessionControlFilter"/>
util:map>
property>
<property name="filterChainDefinitions">
<value>
/login = authc
/index.jsp = anon
/*/register* = anon
/logout = logout
/static/** = anon
/assets/** = anon
/image/** = anon
/images/** = anon
/** = kickout,authc
value>
property>
bean>
这里的客户端js用ajax请求就自己写好了~
0.0
欢迎入群交流:377597358