• shiro+spring


    公司自用的管理系统使用了shiro,但是对于这个登录页面跳转、登录的过程逻辑以及登录成功或者失败的跳转页面一直不理解,查看相关文档资料,整理出一些结果并本地调试测试,记录下备以后回顾之用。

    对于spring+shiro,很多文档都是:搭建环境,然后配置web.xml,shiro spring配置文件,开发自己的realm、shiro的过滤器链以及spring controller等等内容。实际开发中,也是按照这套路来使用的。但是:对于localhost/xxx/login登录请求页面跳转,怎么感觉是直接请求spring而未通过shiro过滤器?

    本地web.xml配置文件部分截图:

    shiro配置:

     spring mvc作为请求控制器,shiro作为权限过滤器,shiro对所有请求url进行判断,并指定相关的过滤器,例如/xxx/login指定的是authc过滤器(验证,这些页面必须验证后才能访问,也就是我们说的登录后才能访问),过滤器逻辑如果抛出异常表示认证失败,过滤器会转向shiroFilter配置的loginUrl地址,认证成功会转向配置的successUrl地址。而转向过后的逻辑将是由springmvc来控制。

    登录时验证:

     1 /**
     2  * 
     3  */
     4 package com.autrade.xxx.shiro;
     5 
     6 import javax.servlet.ServletRequest;
     7 import javax.servlet.ServletResponse;
     8 
     9 import org.apache.commons.lang.StringUtils;
    10 import org.apache.shiro.authc.AuthenticationException;
    11 import org.apache.shiro.authc.AuthenticationToken;
    12 import org.apache.shiro.authc.IncorrectCredentialsException;
    13 import org.apache.shiro.authc.UnknownAccountException;
    14 import org.apache.shiro.subject.Subject;
    15 import org.apache.shiro.web.util.WebUtils;
    16 import org.springframework.stereotype.Service;
    17 
    18 import com.autrade.sptmasterweb.util.FailCacheUtils;
    19 
    20 /**
    21  * 表单验证(包含验证码)过滤类
    22 
    23  *
    24  */
    25 @Service
    26 public class FormAuthenticationFilter extends org.apache.shiro.web.filter.authc.FormAuthenticationFilter {
    27 
    28     public static final String DEFAULT_MESSAGE_PARAM = "message";
    29     
    30 
    31     @Override
    32     protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
    33         AuthenticationToken token = createToken(request, response);
    34         if (token == null) {
    35             String msg = "createToken method implementation returned null. A valid non-null AuthenticationToken " +
    36                     "must be created in order to execute a login attempt.";
    37             throw new IllegalStateException(msg);
    38         }
    39         try {
    40             Long lockTime = FailCacheUtils.isLocked(token.getPrincipal().toString());
    41             if (lockTime>0){
    42                 request.setAttribute(DEFAULT_MESSAGE_PARAM, "错误次数过多,请稍后再试!");
    43                 return true;
    44             }
    45             Subject subject = getSubject(request, response); //代表当前前台传过来的用户
    46             subject.login(token);
    47             return onLoginSuccess(token, subject, request, response);
    48         } catch (AuthenticationException e) {
    49             return onLoginFailure(token, e, request, response);
    50         }
    51     }
    52     /**
    53      * 登录失败调用事件
    54      */
    55     @Override
    56     protected boolean onLoginFailure(AuthenticationToken token,
    57             AuthenticationException e, ServletRequest request, ServletResponse response) {
    58         String className = e.getClass().getName(), message = "";
    59         if (IncorrectCredentialsException.class.getName().equals(className)
    60                 || UnknownAccountException.class.getName().equals(className)){
    61             message = "用户或密码错误, 请重试.";
    62         }
    63         else if (e.getMessage() != null && StringUtils.indexOf(e.getMessage(), "msg:")!=-1){
    64             message = StringUtils.replace(e.getMessage(), "msg:", "");
    65         }
    66         else{
    67             message = "系统出现点问题,请稍后再试!";
    68             e.printStackTrace(); // 输出到控制台
    69         }
    70         request.setAttribute(getFailureKeyAttribute(), className);
    71         request.setAttribute(DEFAULT_MESSAGE_PARAM, message);
    72         String username = WebUtils.getCleanParam(request, FormAuthenticationFilter.DEFAULT_USERNAME_PARAM);
    73         FailCacheUtils.addFailCnt(username);
    74         return true;
    75     }
    76     
    77     @Override
    78     protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request,
    79             ServletResponse response) throws Exception {
    80         String username = WebUtils.getCleanParam(request, FormAuthenticationFilter.DEFAULT_USERNAME_PARAM);
    81         FailCacheUtils.remave(username);
    82         return super.onLoginSuccess(token, subject, request, response);
    83     }
    84     
    85 }

    自定义realm中:

    认证:

    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
         //token令牌,也就相当于一张表格,你要去验证,你就得填个表,里面写好用户名密码,交给公安局的同志给你验证 UsernamePasswordToken token
    = (UsernamePasswordToken) authcToken; InternalUserDownEntity userAcctInfoEntity = internalUserService.findInternalUserInfoByUserName(token.getUsername());if (userAcctInfoEntity!=null) {
           //用户我们可以前面的令牌也就是我说的表格来取的,我们前台提交给公安同志一个表格,里面有用户密码,
           //但需要注意的是,我们在这里并不把表格中的用户密码路数据库中的用户密码进行比较,我们只是根据表格中的用户名把密码查出来,
           //然后把数据库的用户密码放在一个SimpleAuthenticationInfo对象中返回即可,这位公安同志不负责验证,只负责验证的材料 InternalUserAuthEntity userAuthEntity
    = new InternalUserAuthEntity(); userAuthEntity.setUserId(userAcctInfoEntity.getUserId()); ShiroUser shiroUser = new ShiroUser(userAcctInfoEntity.getUserId(), token.getUsername(),token.getUsername(), userAuthEntity); return new SimpleAuthenticationInfo(shiroUser,userAcctInfoEntity.getPassWord(), getName()); } else { return null; } }

    以上准备好比对数据,什么时候验证呢?

    (1)executeLogin中调用subject.isAuthenticated()时

    (2)由于之前的shiro spring配置文件中配置了/login = authc, 配了authc过滤器,shiro会自动调用subject.isAuthenticated()方法完成验证对比。

  • 相关阅读:
    关于 L3 缓存行 cacheLIne 的研究!还是对程序有举足轻重的作用!
    所谓的科学,根本就没有解决问题的根本。如框架,框架再好,也需要内容。
    编译器开发,手动把汇编转 机器码
    测试HTML
    神奇的经历,顶上去保证上帝保佑你!!!!!
    ECS框架研究 ,unity 以及缓存行的研究
    AVX 指令详解 ,还有SSE指令
    关于 Visual Studio 2017 ,或2019 ,Installer 没检测到已安装的程序.以及C++ 创建项目失败
    TCP 协议 精解
    opc 相关组件
  • 原文地址:https://www.cnblogs.com/eric-fang/p/6999811.html
Copyright © 2020-2023  润新知