shiro登录拦截

1. shiro介绍

shiro的程序运行流程图:


shiro登录拦截_第1张图片

Application code:应用程序代码,开发人员编写的代码
Subject:主体,当前用户
SecurityManager:安全管理器,shiro框架的核心对象,管理各个组件
Realm:类似于Dao,负责访问安全数据(用户数据、角色数据、权限数据)

2.shiro的表单认证流程(可以自定义表单认证)

参考http://blog.csdn.net/zcl_love_wx/article/details/51577058

shiro登录拦截_第2张图片

实际中可能会有点差别,灵活处理

1.已经登录,放行
3.未登录,判断是否是登录请求,不是则跳转到登录页面,并保存当前请求
5.是登录请求,并且为get请求,则直接跳转到loginUrl,即登录页面
6.是post请求,说明从登录页面提交了表单,开始表单,realm验证
7.验证失败,则将错误信息存入shiroLoginFailure中,并重新跳转到登录页面,并显示错误信息
8.验证成功则跳转到之前保存的请求,没有则跳转到successUrl指定页面

注意:登录请求/login被拦截进行验证,最后还是会跳到/login的Controller中

3.实际应用到项目中

  1. 导入相关的包,shiro-all.jar
  2. 在web.xml文件中配置Spring用于整合shiro的过滤器
   
        shiroFilter
        org.springframework.web.filter.DelegatingFilterProxy
        true
        
            targetFilterLifecycle
            true
        
    
    
        shiroFilter
        /*
    
  1. 在Spring-mvc中配置一个bean,id和之前过滤器的名称相同

    
        
                
         
        
        
            
                
                
            

        
        
            
                /assets/** = anon
                /*.ico = anon
                /nirvana/** = anon
                /login = authc
                /logout = logout
                /** = authc
            
        
    

具体细节就不再描述了,请百度自行了解

  1. 根据shiro的介绍,配置安全管理器securityManager,及其依赖的相关属性
    
    
        
        
        
    

    
    
         
        
        
        
        
    

    
    
        
        
    

      
      
          
          
    

    
     
        
        
        
        
    

    
    

这里自定义了表单过滤器和登出过滤器

  1. 自定义表单过滤器CustomFormAuthenticationFilter
public class CustomFormAuthenticationFilter extends FormAuthenticationFilter {
   // 创建 Token
    protected CaptchaUsernamePasswordToken createToken(
            ServletRequest request, ServletResponse response) {

        String username = getUsername(request);
        String password = getPassword(request);
        String captcha = getCaptcha(request);
        boolean rememberMe = isRememberMe(request);
        return new CaptchaUsernamePasswordToken(username, password.toCharArray(), rememberMe, captcha);
    }



    // 认证
    protected boolean executeLogin(ServletRequest request,
                                   ServletResponse response) throws Exception {
        CaptchaUsernamePasswordToken token = createToken(request, response);

        try {
           /* doCaptchaValidate((HttpServletRequest) request, token);*/

            Subject subject = getSubject(request, response);
            subject.login(token);

            return onLoginSuccess(token, subject, request, response);
        } catch (AuthenticationException e) {
            return onLoginFailure(token, e, request, response);
        }
    }
}
  1. 自定义登出过滤器
public class CoustomLogoutFilter extends LogoutFilter {

    private static final Logger log = LoggerFactory.getLogger(CoustomLogoutFilter.class);

    public CoustomLogoutFilter() {}

    @Override
    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
        Subject subject = getSubject(request, response);
        String redirectUrl = getRedirectUrl(request, response, subject);
        try {
            subject.logout();
        } catch (SessionException ise) {
            log.debug("Encountered session exception during logout.  This can generally safely be ignored.", ise);
        }

        issueRedirect(request, response, redirectUrl);
        return false;
    }
}
  1. 自定义BosRealm
public class UserRealm extends AuthorizingRealm{
   private static Logger log = LoggerFactory.getLogger(UserRealm.class);
    
    @Autowired
    SysUserInfoServiceImpl userService;
   /**
     * 登录认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
            throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        log.info("登录认证");
        // 通过表单接收的用户名
        String username = token.getUsername();
        String password = token.getPassword().toString();
        if (token.getPassword() != null) {
            password = new String(token.getPassword());
        }
        SysUserInfo user = userService.selectUserByUserName(username);
        if (user != null) {
            //是否通过 域认证
            //boolean flag = ldapAuthentication.authentication(username, password);
            boolean flag = username.equals(user.getSysUsername())&&password.equals(user.getSysPwd());/**/
            if (flag) {
                // 需要验证用户是否在本环境中存在
               //SysUserInfo user = userService.selectUserByUserName(username);
               /*  if (user == null) { // 如果没有此用户, 则添加一个用户
                    user = userService.addNewUser(username);
                } else if (user.getIsDeleted()) {
                    throw new UnknownAccountException("已通过域认证,用户被锁定,请联系管理员。");// 账号锁定
                }
                if (user == null) {
                    throw new UnknownAccountException("已通过域认证,创建用户失败。");
                }*/
                //如果身份认证验证成功,返回一个AuthenticationInfo实现;  
                SimpleAuthenticationInfo info = null;
                try {
                    info = new SimpleAuthenticationInfo(user, password.toCharArray(), user.getSysUsername());
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
                return info;
            } else {
                log.info(username+"用户名或密码错误。");
                throw new UnknownAccountException("用户名或密码错误");
            }
        }else{
             log.info(username+"用户名不存在");
             throw new UnknownAccountException("用户名或密码错误");
        }
    }
 }
  1. 登录controller,LoginController
@Controller
public class LoginController {

    private static Logger log = LoggerFactory.getLogger(LoginController.class);

    /**
     * 访问需要登录的页面时被拦截后,需要跳转到到login页面
     * 结合shiro配置查看
     * @throws IOException
     */
    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public String login(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException {
        log.warn("shiro拦截到需要登录的请求: "+ httpServletRequest.getRequestURI());

        Subject subject = SecurityUtils.getSubject();
        boolean loginStatus = subject.isAuthenticated();
        if (loginStatus) {
            log.warn("已登录状态,返回到主页");
            Cookie coo = new Cookie("loginMessage", null);
            httpServletResponse.addCookie(coo);
            return "redirect:login/index";
        } else {
            log.warn("未登录状态,返回登录页面");
            Cookie cook = new Cookie("loginMessage", null);
            httpServletResponse.addCookie(cook);
            return "/pages/login";
        }
    }

    @RequestMapping(value = "login/index")
    public String toindex(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
        log.warn("登录成功,跳转到主页");
        return "/pages/index";
    }

    /**
     * 登录失败会调用此接口,返回登录界面
     * @throws IOException
     */
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public String loginFail(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException{
        Subject subject = SecurityUtils.getSubject();
        boolean loginStatus = subject.isAuthenticated();
        if (loginStatus) {
            log.warn("已登录状态,返回到主页");
            Cookie coo = new Cookie("loginMessage", null);
            httpServletResponse.addCookie(coo);
            return "redirect:/index";
        } else {
          //登录失败了 提取错误消息
            Exception shiroLoginFailureEx = (Exception) httpServletRequest.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);
            String errorMsg = shiroLoginFailureEx.getMessage();
            log.warn("登录失败后返回login页面");
            Cookie coo = new Cookie("loginMessage", URLEncoder.encode(errorMsg,"UTF-8"));
            httpServletResponse.addCookie(coo);
            return "/pages/login";
        }
    }
}

顺序:提交表单后-->CustomFormAuthenticationFilter-->UserRealm-->LoginController(/login)

你可能感兴趣的:(shiro登录拦截)