shiro认证的流程
来源:互联网 发布:linux从文件命令变量 编辑:程序博客网 时间:2024/04/28 15:30
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-->必须通过认证)
- web.xml中配置一个代理的对象。他会通过spring容器找到filter的工厂来找到真正的filter.
<!--fitler工厂,可以创建不同的 过虑器 -->
<beanid="shiroFilter"class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<propertyname="securityManager"ref="securityManager"/>
<!-- loginUrl会被formAuthenticationFilter判断是不是认证提交 -->
<propertyname="loginUrl" value ="/login.action"/>
<!-- 认证成功统一跳转到first.action,建议不配置,shiro认证成功自动到上一个请求路径 -->
<propertyname="successUrl" value="/first.action"/>
<propertyname="unauthorizedUrl"value="/refuse.jsp"/>
<!-- 自定义认证filter配置 -->
<propertyname="filters">
<map>
<!-- 将自定义 的FormAuthenticationFilter注入shiroFilter中 -->
<entrykey="authc" value-ref="formAuthenticationFilter"/>
</map>
</property>
<!-- 过虑器链定义,从上向下顺序执行,一般将/**放在最下边 -->
<propertyname="filterChainDefinitions">
<value>
<!-- 对静态资源设置匿名访问 -->
/images/** = anon
/js/** = anon
/styles/** = anon
/jfreechart = anon
/test/** =anon
<!-- 验证码,可匿名访问 -->
/validatecode.jsp = anon
<!-- 退出拦截,请求logout.action执行退出操作 -->
/logout.action = logout
<!-- /** = authc 所有url都必须认证通过才可以访问 -->
/** =authc
</value>
</property>
</bean>
理解FormAuthenticationFilter执行流程(重点理解)
loginUrl会被formAuthenticationFilter判断是不是认证提交
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1. formAuthentivationFilter--->底层代码实现 。他的执行流程就是上面那张图的执行流程
protectedbooleanonAccessDenied(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.");
}
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 ;
}
2.自定义的realm--->他是吧用户输入的账号和密码 和 调用realm去数据库中查到的用户名和密码进行比对 。存在的话给认证器返回查到的信息。否则返回null
publicclass customRealm extendsAuthorizingRealm{
@Override
publicbooleansupports(AuthenticationToken token) {
return token instanceof UsernamePasswordToken;
}
@Override
publicString getName() {
return "customRealm" ;
}
@Autowired
privateServiceFacade serviceFacade;
protectedAuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token)throws AuthenticationException {
//首先获取用户输入的账号。根据账号去数据库中查用户。对用户做出判断
String usercode = (String) token.getPrincipal();
//根据 usercode查询用户
SysUser sysUser =serviceFacade.getSysUserService().findSysUserByUserCode(usercode);
if (sysUser==null) {
return null ;
}
String pwd = sysUser.getPwd();
ActiveUser activeUser =serviceFacade.getSysUserService().createUser(usercode);
SimpleAuthenticationInfo simpleAuthenticationInfo =new SimpleAuthenticationInfo(activeUser,pwd, getName());
return simpleAuthenticationInfo;
}
- 最后,是登录的login.action的实现:
1、能够返回一个登陆页面
2、接收post提交
3、接收到认证失败的原因
publicString login() {
HttpServletRequest request =this.getRequest();
// shiro 在认证过程中出现错误后将异常类路径通过request返回
String exceptionClassName = (String) request
.getAttribute("shiroLoginFailure");
if (exceptionClassName != null) {
if (UnknownAccountException.class.getName().equals(
exceptionClassName)) {
// 账号不存在
// 抛出异常
ResultInfo resultInfo = ResultUtil.createFail(Config.MESSAGE,
101,null);
throw new ExceptionResultInfo(resultInfo);
}else if (IncorrectCredentialsException.class.getName().equals(
exceptionClassName)) {
// 用户名或密码 错误
ResultInfo resultInfo = ResultUtil.createFail(Config.MESSAGE,
114,null);
throw new ExceptionResultInfo(resultInfo);
}else if ("randomCodeError".equals(exceptionClassName)) {
// 提供验证码错误
ResultInfo resultInfo = ResultUtil.createFail(Config.MESSAGE,
113,null);
throw new ExceptionResultInfo(resultInfo);
}else {
// 最终在异常处理器生成未知错误
ResultInfo resultInfo = ResultUtil.createFail(Config.MESSAGE,
900,null);
throw new ExceptionResultInfo(resultInfo);
}
}
// 返回一个登陆页面
return "login" ;
注意:
解决页面的验证码的问题----》自定义一个类 继承FormAuthenticationFilter这个拦截器 在执行认证之前,加入对验证码的校验
protectedbooleanonAccessDenied(ServletRequest request,
ServletResponse response)throws Exception {
// 首先将ServletRequest强转成 httprequest
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
if (isLoginRequest(request, response)) {// 判读是否是认证的请求 .是认证请求
if (isLoginSubmission(request, response)) {// 是否是post请求
if (log .isTraceEnabled()) {
log.trace("Login submission detected. Attempting to execute login.");
}
HttpSession session = httpServletRequest.getSession();
// 这个是正确的验证码
String validateCode = (String) session
.getAttribute("validateCode");
// 获得页面输入的验证码
String randomCode = httpServletRequest
.getParameter("validateCode");
// 判断
if (randomCode != null&& validateCode != null
&& !randomCode.equals(validateCode)) {
// 校验失败的话,通过shiroLoginFailure设置到request中
httpServletRequest.setAttribute("shiroLoginFailure",
"randomCodeError");
// 转发到登陆页面
return true ;
}
return executeLogin(request, response);// 执行认证,执行认证之前,加入验证码的认证
此时认证成功后页面不会发生跳转---》解决
// 解决页面跳转的问题
protectedboolean onLoginSuccess(AuthenticationToken token,
Subject subject, ServletRequest request, ServletResponse response)
throws Exception {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
// 如果是 ajax请求的话让它输出 json数据,否则执行原来的方法进行重定向
if ("XMLHttpRequest".equalsIgnoreCase(httpServletRequest
.getHeader("X-Requested-With"))) {// 是ajax请求
// 输出 json
// ajax 请求
response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8" );
response.getWriter()
.write("{\"resultInfo\":{\"type\":\"1\",\"messageCode\":\"906\",\"message\":\"登陆成功\"}}");
return false ;
}else {
// 使用原来的代码进行重定向
issueSuccessRedirect(request, response);
return false ;
}
}
在applicationContext-shiro.xml中 配置authc为CustomFormAuthenticationFilter
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0 0
- shiro认证的流程
- Shiro身份认证的流程
- shiro框架认证方法的流程
- shiro认证授权流程
- apache shiro 登录认证流程
- Shiro源码分析----认证流程
- Shiro源码分析----认证流程
- 【shiro】授权和认证流程
- shiro的认证思路分析(即登录,流程)
- Shiro认证流程和授权流程
- shiro认证的过程
- Shiro 的身份认证
- 源码分析shiro认证授权流程
- 源码分析shiro认证授权流程
- 源码分析shiro认证授权流程
- 源码分析shiro认证授权流程
- Shiro身份认证流程,securityManager源码解析
- Shiro认证授权业务软件实现流程
- hibernate反向生成奇葩错误(续)
- leetcode-343. Integer Break
- 那些年我们错过的响应式编程
- 基于fisher线性判别法的分类器设计
- 用两个栈实现队列
- shiro认证的流程
- 提升 MongoDB 安全性的 10 个提示
- LightOJ - 1245 Harmonic Number (II) 分块加速
- static 和 final 回顾
- 忙忙碌碌
- Ubuntu下安装PyV8
- leetcode-268. Missing Number
- 深入浅出ES6(三):生成器 Generators
- SSH三大框架的整合 (基于xml)