Java結合SpringBoot攔截器實現簡單的登陸認證模塊

Java結合SpringBoot攔截器實現簡單的登陸認證模塊

以前在作項目時須要實現一個簡單的登陸認證的功能,就尋思着使用Spring Boot的攔截器來實現,在此記錄一下個人整個實現過程,源碼見文章底部。javascript

1. 環境搭建

IntelliJ IDEA + Java8 + Spring Boot + Tomcat
我將以前項目中的登陸模塊抽離出來,單獨放在了一個新建的Spring Boot項目中;
整個項目的主要結構以下:
項目結構css

參考資料:使用IDEA建立Spring Boot項目html

2. 代碼詳解

2.1 前端代碼

以前項目裏別的小夥伴已經寫好了一個簡單的登陸框樣式表(login.css)和一些image圖,我這裏就順手拿來用了,但願哪天你見了眼熟別拍我…
login.vm代碼:
注意前端傳遞給後端Controller的password值並不是用戶實際輸入的密碼!
實際傳遞的是用戶名 + 密碼(統一小寫)組合的字符串的md5信息值;
這樣在先後臺數據傳遞及後臺數據保存時傳遞和保存的都不是用戶的真實密碼值,能夠必定程度提高安全性及規避某些風險;前端

更多資料可參考:Web前端密碼加密是否有意義java

<html>
<head>
    <title>系統登陸</title>
    <meta charset="utf-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="author" content="Dreamer-1">
    <meta name="renderer" content="webkit" />

    <link href="/css/login/login.css" rel="stylesheet">
    <script type="text/javascript" src="/js/login/jquery/jquery.min.js?v=20170207"></script>
    <script type="text/javascript" src="/js/login/md5/md5.js"></script>
</head>

<body>
    <form name="form1" method="post" action="/login" id="form1" onsubmit="return checkLogin();">
        <div id="main">
        <div class="wrapper">
            <div class="login-hd"></div>
            <div class="login-body">
                <div class="logo">
                    <span class="icon-logo"></span>
                </div>
                <div class="box">
                    <div class="login-item">
                        <span class="icon-user"></span>
                        <input name="username" type="text" id="username" class="login-input" tabindex="1" maxlength="50" placeholder="請輸入用戶名" />

                    </div>
                    <div class="login-item mt35">
                        <span class="icon-pwd"></span>
                        <input type="password" id="password"  class="login-input" tabindex="2" maxlength="32" placeholder="請輸入密碼"/>
                        <input type="hidden" id="hidePwd" name="password">
                    </div>
                    <div class="login-forget" style="visibility:hidden">
                        <a href="#">忘記密碼</a>
                    </div>

                    <input type="submit" name="Logon" value="登陸" id="Logon" tabindex="3" class="login-btn" />
                    <div class="login-bottom">
                        <div class="msg"  style="display:none;" >
                            <span class="icon-err"></span>
                            <span id="message"></span>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        </div>
    </form>

    <script type="text/javascript">
        // onsubmit值爲true時,提交表單,不然顯示錯誤信息
        // 生成用戶名+密碼組合的md5值,並設置傳給後端的密碼爲該md5值
        function checkLogin() {
        var name = $("#username").val().toLowerCase();
        var pwd = $("#password").val().toLowerCase();
        if(name.trim()=="" || pwd.trim()=="") {
            $("#message").text("請輸入用戶名和密碼");
            $('.msg').show();
            return false;
        }else {
            $('.msg').hide();
        }

        var md5info = name + pwd;
        $('#hidePwd').val(md5(md5info));
        //$("#password").val();
        return true;
    }
    </script>
</body>
</html>

welcome.vm代碼
登陸成功後顯示welcome.vm頁的內容,這個頁面很簡單:jquery

<h1 align="center">登陸成功!!!</h1>

<br>
<h3><a href="/loginout"><font color="red">退出登陸</font></a></h3>

2.2 後端代碼

後端代碼相較於前端要複雜一些,讓咱們來一一拆解;web

2.2.1 程序入口

ManApplication.java是整個程序的主入口,由於其上打了@SpringBootApplication的註解;
注意:Spring Boot項目在tomcat上部署運行時,ManApplication須要繼承SpringBootServletInitializer
ManApplication.java代碼:spring

/**
 * @SpringBootApplication 註解標明該類是本程序的入口
 */
@SpringBootApplication
public class ManApplication extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(ManApplication.class);
    }

    public static void main(String[] args) {
        SpringApplication.run(ManApplication.class, args);
    }
}
2.2.2 Controller

IndexViewController.java類裏就是簡單的URL映射;chrome

/**
 * Created with logindemo.
 * Author: dreamer-1
 * Email: zhong--lei@outllok.com
 * Date: 2018/5/13
 * Time: 下午2:58
 * Description:
 */
@Controller
public class IndexViewController {
    /**
     * 登陸
     * @return
     */
    @GetMapping("/")
    public String index() {
        return "login";
    }

    /**
     * 歡迎頁
     * @return
     */
    @GetMapping("/welcome")
    public String welcome() {
        return "welcome";
    }
}

LoginViewController.java類接收前端傳過來的username和password,進行簡單的校驗和重定向;
此處爲了簡單就只設置了一個正確的帳號和密碼用於校驗,你後續使用時能夠結合本身的實際需求來擴充整個校驗邏輯(好比經過專門的表來存儲用戶登陸信息等);
用戶名和密碼校驗經過後會在當前會話的session中放入一個登陸標識,以表示當前用戶已經登陸;在退出登陸或會話超時時銷燬該標識;後端

/**
 * Created with logindemo.
 * Author: dreamer-1
 * Email: zhong--lei@outllok.com
 * Date: 2018/5/13
 * Time: 下午2:49
 * Description:
 */
@Controller
public class LoginViewController {

    // 預先設置好的正確的用戶名和密碼,用於登陸驗證
    private String rightUserName = "admin";
    private String rightPassword = "admin";

    /**
     * 登陸校驗
     *
     * @param request
     * @return
     */
    @RequestMapping("/login")
    public String login(HttpServletRequest request) {
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        if (null == username || null == password) {
            return "redirect:/";
        }

        // 前端傳回的密碼實際爲用戶輸入的:用戶名(小寫)+ 密碼(小寫)組合的字符串生成的md5值
        // 此處先經過後臺保存的正確的用戶名和密碼計算出正確的md5值,而後和前端傳回來的做比較
        String md5info = rightUserName.toLowerCase() + rightPassword.toLowerCase();
        String realPassword = DigestUtils.md5DigestAsHex(md5info.getBytes());
        if (!password.equals(realPassword)) {
            return "redirect:/";
        }

        // 校驗經過時,在session裏放入一個標識
        // 後續經過session裏是否存在該標識來判斷用戶是否登陸
        request.getSession().setAttribute("loginName", "admin");
        return "redirect:/welcome";
    }

    /**
     * 註銷登陸
     *
     * @param request
     * @return
     */
    @RequestMapping("/loginout")
    public String loginOut(HttpServletRequest request) {
        request.getSession().invalidate();
        return "redirect:/";
    }

}
2.2.3 Interceptor

LoginInterceptor.java是整個登陸認證模塊中的核心類之一,它實現了HandlerInterceptor類,由它來攔截並過濾到來的每個請求;它的三個方法能分別做用於每一個請求的不一樣生命週期,你能夠根據本身的須要來加入相應的處理邏輯;

/**
 * Created with logindemo.
 * Author: dreamer-1
 * Email: zhong--lei@outllok.com
 * Date: 2018/5/13
 * Time: 下午2:58
 * Description:
 */
public class LoginInterceptor implements HandlerInterceptor {

    /**
     * 在請求被處理以前調用
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 檢查每一個到來的請求對應的session域中是否有登陸標識
        Object loginName = request.getSession().getAttribute("loginName");
        if (null == loginName || !(loginName instanceof String)) {
            // 未登陸,重定向到登陸頁
            response.sendRedirect("/");
            return false;
        }
        String userName = (String) loginName;
        System.out.println("當前用戶已登陸,登陸的用戶名爲: " + userName);
        return true;
    }

    /**
     * 在請求被處理後,視圖渲染以前調用
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    /**
     * 在整個請求結束後調用
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}
2.2.4 Configuration

LoginConfiguration.java是另外一個核心類之一,它實現了WebMvcConfigurer類,負責註冊並生效咱們本身定義的攔截器配置;
在這裏要注意定義好攔截路徑和排除攔截的路徑;

WebMvcConfigurerAdapter其實還能夠作不少其餘的事,包括添加自定義的視圖控制器等等,詳見這裏

/**
 * Created with logindemo.
 * Author: dreamer-1
 * Email: zhong--lei@outllok.com
 * Date: 2018/5/13
 * Time: 下午2:58
 * Description:
 */
@Configuration
public class LoginConfiguration implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 註冊攔截器
        LoginInterceptor loginInterceptor = new LoginInterceptor();
        InterceptorRegistration loginRegistry = registry.addInterceptor(loginInterceptor);
        // 攔截路徑
        loginRegistry.addPathPatterns("/**");
        // 排除路徑
        loginRegistry.excludePathPatterns("/");
        loginRegistry.excludePathPatterns("/login");
        loginRegistry.excludePathPatterns("/loginout");
        // 排除資源請求
        loginRegistry.excludePathPatterns("/css/login/*.css");
        loginRegistry.excludePathPatterns("/js/login/**/*.js");
        loginRegistry.excludePathPatterns("/image/login/*.png");
    }
}

3. 踩坑與填坑

3.1 屢次重定向與Circle view path錯誤

剛開始程序部署至tomcat裏運行時,理所固然的出現了意想不到的狀況,詳情以下:
啓動時localhost:8080顯示:
重定向次數過多

後臺一直報錯:
template might not exist

經過斷點調試,發現啓動後不停地進入IndexViewController中的「/」這個URL映射裏;
手動指定訪問路徑爲 localhost:8080/welcome 時後臺報錯:
cycle-view-path

解決辦法:

  1. 在pom文件中導入thymeleaf依賴:
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
  1. 在application.properties裏添加以下配置:
spring.thymeleaf.prefix=classpath:/templates/
    spring.thymeleaf.suffix=.vm

我猜測多是個人view文件都以.vm結尾,thymeleaf默認找的是.html結尾的視圖,因此一直找不到;
有知道的大神能夠在下面留言詳細講解一下 ^_^

4. 大功告成

4.1 運行截圖

未登陸狀況下訪問 localhost:8080/welcome 等非登陸頁面時會自動跳轉到登陸頁面:
運行截圖

4.2 源碼下載

戳這裏下載我喲

相關文章
相關標籤/搜索