shiro认证的流程
2016-04-28 22:56
309 查看
3.1shiro认证流程(掌握!!!)
1、subject.login(token);
token:令牌,包括账号和密码
token是根据当前用户请求的账号和密码去构造!
2、securityManager.login(token)
3、Authenticator.login(token) (重点理解部分)
Authenticator获取到用户输入的账号和密码。
Authenticator去调用realm从数据源中获取正确的账号和密码。
realm:在没有自定义realm时候,shiro使用自定义的CustomRealm。
CustomRealm通过token获取请求的账号,根据账号去查询数据。
如果CustomRealm根据用户请求的账号从数据库没有找到记录,CustomRealm给认证器返回NULL,认证器抛出异常UnknownAccountException (账号不存在)
如果CustomRealm根据用户请求的账号从数据库找到记录了,将账号对应的密码 给认证器返回,认证器拿realm返回的正确的密码 和token中输入的密码进行比对,如果一致则认证通过,否则抛出异常 IncorrectCredentialsException(密码 错误)
shiro框架的方式和spring整合来实现用户的认证
web.xml中配置一个代理的对象。他会通过spring容器找到filter的工厂来找到真正的filter.
<!--
shiro过虑器,DelegatingFilterProxy通过代理模式通过spring容器中的filter工厂创建真正的 fitler -->
<filter
>
<filter-name>
shiroFilter</filter-name
>
<filter-class>
org.springframework.web.filter.DelegatingFilterProxy</filter-class
>
<!-- 设置true由 servlet容器控制filter的生命周期 -->
<init-param>
<param-name>
targetFilterLifecycle</param-name
>
<param-value>
true</
param-value>
</init-param>
<!-- 设置spring容器filter工厂的bean id,如果不设置则找与filter-name一致的bean-->
<init-param>
<param-name>
targetBeanName</param-name
>
<param-value>
shiroFilter</param-value
>
</init-param>
</filter
>
<filter-mapping
>
<filter-name>
shiroFilter</filter-name
>
<url-pattern>
/*</
url-pattern>
</filter-mapping
>
applicationContext-shiro.xml中,有很多的filter。都是按顺序执行的 : anno(公开的放行 logout-->退出 auth-->必须通过认证)
理解FormAuthenticationFilter执行流程(重点理解)
[align=left] loginUrl会被formAuthenticationFilter判断是不是认证提交[/align]
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1. formAuthentivationFilter--->底层代码实现 。他的执行流程就是上面那张图的执行流程
2.自定义的realm--->他是吧用户输入的账号和密码 和 调用realm去数据库中查到的用户名和密码进行比对 。存在的话给认证器返回查到的信息。否则返回null
最后,是登录的login.action的实现:
1、能够返回一个登陆页面
2、接收post提交
3、接收到认证失败的原因
注意:
解决页面的验证码的问题----》自定义一个类 继承FormAuthenticationFilter这个拦截器 在执行认证之前,加入对验证码的校验
protected
boolean
onAccessDenied(ServletRequest request,
ServletResponse response)
throws
Exception {
// 首先将ServletRequest强转成 httprequest
[align=left] HttpServletRequest httpServletRequest = (HttpServletRequest) request;[/align]
[align=left]
[/align]
if
(isLoginRequest(request, response)) {// 判读是否是认证的请求 .是认证请求
if
(isLoginSubmission(request, response)) {// 是否是post请求
if
(log
.isTraceEnabled()) {
log.trace("Login submission detected. Attempting to execute login.");
[align=left] }[/align]
[align=left]
[/align]
[align=left] HttpSession session = httpServletRequest.getSession();[/align]
// 这个是正确的验证码
[align=left] String validateCode = (String) session[/align]
.getAttribute(
"validateCode");
// 获得页面输入的验证码
[align=left] String randomCode = httpServletRequest[/align]
.getParameter(
"validateCode");
// 判断
if
(randomCode != null
&& validateCode !=
null
[align=left] && !randomCode.equals(validateCode)) {[/align]
// 校验失败的话,通过shiroLoginFailure设置到request中
httpServletRequest.setAttribute(
"shiroLoginFailure",
"randomCodeError");
// 转发到登陆页面
return
true ;
[align=left] }[/align]
[align=left]
[/align]
return
executeLogin(request, response);// 执行认证,执行认证之前,加入验证码的认证
此时认证成功后页面不会发生跳转---》解决
[align=left]// 解决页面跳转的问题[/align]
protected
boolean
onLoginSuccess(AuthenticationToken token,
[align=left] Subject subject, ServletRequest request, ServletResponse response)[/align]
throws
Exception {
[align=left] HttpServletRequest httpServletRequest = (HttpServletRequest) request;[/align]
// 如果是 ajax请求的话让它输出 json数据,否则执行原来的方法进行重定向
if ("XMLHttpRequest"
.equalsIgnoreCase(httpServletRequest
.getHeader(
"X-Requested-With"))) {// 是ajax请求
// 输出 json
// ajax 请求
response.setCharacterEncoding(
"utf-8");
response.setContentType(
"application/json;charset=utf-8"
);
[align=left] response.getWriter()[/align]
.write(
"{\"resultInfo\":{\"type\":\"1\",\"messageCode\":\"906\",\"message\":\"登陆成功\"}}"
);
return
false ;
}
else
{
// 使用原来的代码进行重定向
[align=left] issueSuccessRedirect(request, response);[/align]
[align=left][/align]
return
false ;
[align=left] }[/align]
[align=left][/align]
[align=left] }[/align]
[align=justify]在applicationContext-shiro.xml中 配置authc为CustomFormAuthenticationFilter[/align]
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1、subject.login(token);
token:令牌,包括账号和密码
token是根据当前用户请求的账号和密码去构造!
2、securityManager.login(token)
3、Authenticator.login(token) (重点理解部分)
Authenticator获取到用户输入的账号和密码。
Authenticator去调用realm从数据源中获取正确的账号和密码。
realm:在没有自定义realm时候,shiro使用自定义的CustomRealm。
CustomRealm通过token获取请求的账号,根据账号去查询数据。
如果CustomRealm根据用户请求的账号从数据库没有找到记录,CustomRealm给认证器返回NULL,认证器抛出异常UnknownAccountException (账号不存在)
如果CustomRealm根据用户请求的账号从数据库找到记录了,将账号对应的密码 给认证器返回,认证器拿realm返回的正确的密码 和token中输入的密码进行比对,如果一致则认证通过,否则抛出异常 IncorrectCredentialsException(密码 错误)
shiro框架的方式和spring整合来实现用户的认证
web.xml中配置一个代理的对象。他会通过spring容器找到filter的工厂来找到真正的filter.
<!--
shiro过虑器,DelegatingFilterProxy通过代理模式通过spring容器中的filter工厂创建真正的 fitler -->
<filter
>
<filter-name>
shiroFilter</filter-name
>
<filter-class>
org.springframework.web.filter.DelegatingFilterProxy</filter-class
>
<!-- 设置true由 servlet容器控制filter的生命周期 -->
<init-param>
<param-name>
targetFilterLifecycle</param-name
>
<param-value>
true</
param-value>
</init-param>
<!-- 设置spring容器filter工厂的bean id,如果不设置则找与filter-name一致的bean-->
<init-param>
<param-name>
targetBeanName</param-name
>
<param-value>
shiroFilter</param-value
>
</init-param>
</filter
>
<filter-mapping
>
<filter-name>
shiroFilter</filter-name
>
<url-pattern>
/*</
url-pattern>
</filter-mapping
>
applicationContext-shiro.xml中,有很多的filter。都是按顺序执行的 : anno(公开的放行 logout-->退出 auth-->必须通过认证)
<!-- fitler工厂,可以创建不同的 过虑器 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean" > <property name= "securityManager" ref="securityManager" /> <!-- loginUrl会被formAuthenticationFilter判断是不是认证提交 --> <property name= "loginUrl" value ="/login.action" /> <!-- 认证成功统一跳转到first.action,建议不配置, shiro认证成功自动到上一个请求路径 --> <property name= "successUrl" value="/first.action" /> <property name= "unauthorizedUrl" value="/refuse.jsp" /> <!-- 自定义认证filter配置 --> <property name= "filters"> <map> <!-- 将自定义 的FormAuthenticationFilter注入shiroFilter中 --> <entry key= "authc" value-ref="formAuthenticationFilter" /> </map> </property> <!-- 过虑器链定义,从上向下顺序执行,一般将/**放在最下边 --> <property name= "filterChainDefinitions" > <value> <!-- 对静态资源设置匿名访问 --> [align=left] /images/** = anon[/align] / js/** = anon [align=left] /styles/** = anon[/align] / jfreechart = anon [align=left] /test/** =anon[/align] <!-- 验证码,可匿名访问 --> [align=left] /validatecode.jsp = anon[/align] [align=left] [/align] <!-- 退出拦截,请求logout.action执行退出操作 --> [align=left] /logout.action = logout[/align] [align=left] [/align] <!-- /** = authc 所有url都必须认证通过才可以访问 --> /** = authc </value> </property> </bean > |
理解FormAuthenticationFilter执行流程(重点理解)
[align=left] loginUrl会被formAuthenticationFilter判断是不是认证提交[/align]
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1. formAuthentivationFilter--->底层代码实现 。他的执行流程就是上面那张图的执行流程
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { if (isLoginRequest(request, response)) { if (isLoginSubmission(request, response)) { if (log .isTraceEnabled()) { log.trace("Login submission detected. Attempting to execute login."); [align=left] }[/align] return executeLogin(request, response); } else { if (log .isTraceEnabled()) { log.trace("Login page view." ); [align=left] }[/align] //allow them to see the login page ;) return true ; [align=left] }[/align] } else { if (log .isTraceEnabled()) { log.trace("Attempting to access a path which requires authentication. Forwarding to the " + "Authentication url [" + getLoginUrl() + "]" ); [align=left] }[/align] [align=left] [/align] [align=left] saveRequestAndRedirectToLogin(request, response);[/align] return false ; [align=left] }[/align] |
2.自定义的realm--->他是吧用户输入的账号和密码 和 调用realm去数据库中查到的用户名和密码进行比对 。存在的话给认证器返回查到的信息。否则返回null
public class customRealm extends AuthorizingRealm{ [align=left] [/align] [align=left] @Override[/align] public boolean supports(AuthenticationToken token) { return token instanceof UsernamePasswordToken; [align=left] }[/align] [align=left] [/align] [align=left] @Override[/align] public String getName() { return "customRealm" ; [align=left] }[/align] [align=left] [/align] [align=left] @Autowired[/align] private ServiceFacade serviceFacade; [align=left] [/align] protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken token) throws AuthenticationException { //首先获取用户输入的账号。根据账号去数据库中查用户。对用户做出判断 [align=left] String usercode = (String) token.getPrincipal();[/align] //根据 usercode查询用户 SysUser sysUser = serviceFacade.getSysUserService().findSysUserByUserCode(usercode); if (sysUser==null) { return null ; [align=left] }[/align] [align=left] String pwd = sysUser.getPwd();[/align] ActiveUser activeUser = serviceFacade.getSysUserService().createUser(usercode); SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(activeUser,pwd, getName()); return simpleAuthenticationInfo; [align=left] }[/align] [align=left] [/align] [align=left] [/align] |
1、能够返回一个登陆页面
2、接收post提交
3、接收到认证失败的原因
public String login() { HttpServletRequest request = this.getRequest(); // shiro 在认证过程中出现错误后将异常类路径通过request返回 [align=left] String exceptionClassName = (String) request[/align] .getAttribute( "shiroLoginFailure"); if (exceptionClassName != null) { if (UnknownAccountException.class .getName().equals( [align=left] exceptionClassName)) {[/align] // 账号不存在 // 抛出异常 [align=left] ResultInfo resultInfo = ResultUtil.createFail(Config.MESSAGE,[/align] 101, null); throw new ExceptionResultInfo(resultInfo); } else if (IncorrectCredentialsException.class .getName().equals( [align=left] exceptionClassName)) {[/align] // 用户名或密码 错误 [align=left] ResultInfo resultInfo = ResultUtil.createFail(Config.MESSAGE,[/align] 114, null); throw new ExceptionResultInfo(resultInfo); } else if ("randomCodeError" .equals(exceptionClassName)) { // 提供验证码错误 [align=left] ResultInfo resultInfo = ResultUtil.createFail(Config.MESSAGE,[/align] 113, null); throw new ExceptionResultInfo(resultInfo); } else { // 最终在异常处理器生成未知错误 [align=left] ResultInfo resultInfo = ResultUtil.createFail(Config.MESSAGE,[/align] 900, null); throw new ExceptionResultInfo(resultInfo); [align=left] }[/align] [align=left] }[/align] [align=left]// 返回一个登陆页面[/align] return "login" ; |
解决页面的验证码的问题----》自定义一个类 继承FormAuthenticationFilter这个拦截器 在执行认证之前,加入对验证码的校验
protected
boolean
onAccessDenied(ServletRequest request,
ServletResponse response)
throws
Exception {
// 首先将ServletRequest强转成 httprequest
[align=left] HttpServletRequest httpServletRequest = (HttpServletRequest) request;[/align]
[align=left]
[/align]
if
(isLoginRequest(request, response)) {// 判读是否是认证的请求 .是认证请求
if
(isLoginSubmission(request, response)) {// 是否是post请求
if
(log
.isTraceEnabled()) {
log.trace("Login submission detected. Attempting to execute login.");
[align=left] }[/align]
[align=left]
[/align]
[align=left] HttpSession session = httpServletRequest.getSession();[/align]
// 这个是正确的验证码
[align=left] String validateCode = (String) session[/align]
.getAttribute(
"validateCode");
// 获得页面输入的验证码
[align=left] String randomCode = httpServletRequest[/align]
.getParameter(
"validateCode");
// 判断
if
(randomCode != null
&& validateCode !=
null
[align=left] && !randomCode.equals(validateCode)) {[/align]
// 校验失败的话,通过shiroLoginFailure设置到request中
httpServletRequest.setAttribute(
"shiroLoginFailure",
"randomCodeError");
// 转发到登陆页面
return
true ;
[align=left] }[/align]
[align=left]
[/align]
return
executeLogin(request, response);// 执行认证,执行认证之前,加入验证码的认证
此时认证成功后页面不会发生跳转---》解决
[align=left]// 解决页面跳转的问题[/align]
protected
boolean
onLoginSuccess(AuthenticationToken token,
[align=left] Subject subject, ServletRequest request, ServletResponse response)[/align]
throws
Exception {
[align=left] HttpServletRequest httpServletRequest = (HttpServletRequest) request;[/align]
// 如果是 ajax请求的话让它输出 json数据,否则执行原来的方法进行重定向
if ("XMLHttpRequest"
.equalsIgnoreCase(httpServletRequest
.getHeader(
"X-Requested-With"))) {// 是ajax请求
// 输出 json
// ajax 请求
response.setCharacterEncoding(
"utf-8");
response.setContentType(
"application/json;charset=utf-8"
);
[align=left] response.getWriter()[/align]
.write(
"{\"resultInfo\":{\"type\":\"1\",\"messageCode\":\"906\",\"message\":\"登陆成功\"}}"
);
return
false ;
}
else
{
// 使用原来的代码进行重定向
[align=left] issueSuccessRedirect(request, response);[/align]
[align=left][/align]
return
false ;
[align=left] }[/align]
[align=left][/align]
[align=left] }[/align]
[align=justify]在applicationContext-shiro.xml中 配置authc为CustomFormAuthenticationFilter[/align]
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
相关文章推荐
- 用两个栈实现队列
- 迎来史上最好的编辑器:VSC,没有之一
- Linux系统的理解及学习Linux内核的心得
- HBuilder支持jquery、zepto、angular、ext、dojo 等js框架的提示吗
- 【Leetcode】:230. Kth Smallest Element in a BST 问题 in JAVA
- leetcode-343. Integer Break
- linux上破解myeclipse2014
- 基于fisher线性判别法的分类器设计
- Swift初始化方法顺序
- 九、堆与优先队列---(2)堆插入
- hibernate反向生成奇葩错误(续)
- jQuery学习小问题记录
- Matlab调用ZXing的详细步骤——二维码生成
- leetcode-319. Bulb Switcher
- Xcode高效开发 ——快捷键
- 文件打包与压缩
- hbase学习
- redis 的使用 (基础, key操作, string类型操作)
- 团队项目-个人博客-4.28
- Android反编译