原文来自:http://blog.csdn.net/u013632755/article/details/51485158 感谢博主的分享
用了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 { Map<String,String> params = new HashMap<String,String>(); 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"))) { 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"))) { 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) { e1.printStackTrace(); } return false; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
上面这个类的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>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
接下来,你就可以直接在客户端用js请求login了~