1. 程式人生 > >shiro學習筆記(6)--spring整合及可能遇到的問題小結

shiro學習筆記(6)--spring整合及可能遇到的問題小結

上篇spring整合shiro後續…
spring整合shiro主要是org.apache.shiro.web.filter.authc.FormAuthenticationFilter類。
1、controller

@Controller
public class HelloSsm {

    @RequestMapping(value = {"/","tologin.do"})
    public String tologin(){
        return "models/sys/login";
    }

    @RequestMapping("login.do")
    public String login(Model model, User user, HttpServletRequest request){
        //進入login.do說明shiro認證失敗
        /**
         * 在FormAuthenticationFilter中,將認證失敗的異常類資訊儲存在request的shiroLoginFailur中
         */
        String className = (String) request.getAttribute("shiroLoginFailure");
        if(UnknownAccountException.class.getName().equals(className)){
            System.out.println("賬號有誤!");
        }else if(DisabledAccountException.class.getName().equals(className)){
            System.out.println("禁用的賬號!");
        }else if(ExcessiveAttemptsException.class.getName().equals(className)){
            System.out.println("登入次數過多!");
        }else if(ConcurrentAccessException.class.getName().equals(className)){
            System.out.println("併發訪問異常!");
        }else if(IncorrectCredentialsException.class.getName().equals(className)){
            System.out.println("密碼錯誤!");
        }else if(ExpiredCredentialsException.class.getName().equals(className)){
            System.out.println("密碼過期!");
        }else {
            System.out.println("系統錯誤");
        }
        String message = "賬號或密碼錯誤,請重試...";
        request.setAttribute("message",message);
        return "models/sys/login";
    }

    @RequestMapping("index.do")
    public String index(Model model,HttpServletRequest request){
        User user = (User) SecurityUtils.getSubject().getPrincipal();
        if(user!=null) {
            request.setAttribute("username", user.getUsername());
        }
        return "models/sys/index";
    }
}

2、login.jsp
注意:form提交表單需要post方式,否則FormAuthenticationFilter將無法進入自定義realm中的認證方法。

<form action="login.do" style="background-color: burlywood" method="post">
    username:<input type="text" name="username"><br/>
    password:<input type="password" name="password"><br/>
    <c:if test="${message!=null && message!=''}">
        <input type="text" value="${message}" style="font-weight: bold;font-size:10px;">
    </c:if>
    <input type="submit" value="login">
</form>

3、跑起來,你可能會碰到的坑~
(1)無法進入realm的認證方法
查看錶單提交方式是否是post
(2)無法注入service
這個問題曾困擾了好久,原因有很多。
首先是web容器中filter載入優先於servlet,為此在filter中無法使用spring註解,需要將spring載入優先順序設定更高(當然也可能無效)
其次:仍然無效時需要通過工具類獲取spring上下文,以獲取需要注入的service

loginService = SpringBeanFactoryUtils.getBean(LoginService.class);
@Component
public class SpringBeanFactoryUtils implements ApplicationContextAware{

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (SpringBeanFactoryUtils.applicationContext == null) {
            SpringBeanFactoryUtils.applicationContext = applicationContext;
        }
    }

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    //根據名稱(@Resource 註解)
    public static Object getBean(String name) {
        return getApplicationContext().getBean(name);
    }

    //根據型別(@Autowired)
    public static <T> T getBean(Class<T> clazz) {
        return getApplicationContext().getBean(clazz);
    }

    public static <T> T getBean(String name, Class<T> clazz) {
        return getApplicationContext().getBean(name, clazz);
    }
}

(3)loginUrl和successUrl及filterChainDefinitions配置
注意路徑設定與認證不要衝突
(4)認證失敗
首先是確保是否獲取了完整的使用者資訊。在realm的認證入參AuthenticationToken中檢視
其次是斷點跟蹤認證是否正常
(5)認證完成跳轉路徑
認證後跳轉路徑是根據shiro的xml配置確定的,個人建議最好設定successUrl。這樣當認證失敗時可完整記錄失敗異常資訊
說一下認證失敗時資訊獲取:

/**
   * 在FormAuthenticationFilter中,將認證失敗的異常類資訊儲存在request的shiroLoginFailur中
   */
        String className = (String) request.getAttribute("shiroLoginFailure");