1. 程式人生 > >spring security custom loginPage + freemarker

spring security custom loginPage + freemarker

最近在做一個專案,使用spring security來做登入的身份驗證,折騰了很久,也搜了很多資料終於把這部分內容做的差不多了,在這裡來做一個總結。

專案所使用的工具有:

  1. Spring 4.2.2.RELEASE
  2. Spring Security 4.0.3.RELEASE
  3. MAVEN 3
  4. JDK 1.7
  5. tomcat 8

這裡有一個很簡單的使用spring-security的專案,Spring-Security-Custom-LoginPage,但是這個專案使用的是預設的登入頁面和設定,在本專案中使用的是自定義的登入頁面。

1、框架的搭建

首先需要進行Spring框架的搭建,在這裡不多做介紹,需要依賴一些基礎的spring包。

2、Spring Security Configuration

第二步需要進行Spring Security框架的搭建,首先需要在maven中依賴相應的包,分別在properties中和dependencymanagement中加入相應的內容。

<!-- spring security -->
<properties>
        <spring.security.version>4.0.3.RELEASE</spring.security.version>
</properties>

<dependencyManagement
>
<dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>${spring.security.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId
>
<artifactId>spring-security-core</artifactId> <version>${spring.security.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>${spring.security.version}</version> </dependency> </dependencyManagement>

引用完成後需要進行Spring Security的配置,加入spring-security.xml檔案,並在web.xml中引用相應的配置檔案

<!-- web.xml -->
<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>classpath*:application*.xml,</param-value>
</context-param>
<!-- application-spring-security.xml -->
<beans:beans xmlns="http://www.springframework.org/schema/security"
             xmlns:beans="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/security
    http://www.springframework.org/schema/security/spring-security.xsd">

    <http auto-config="true">
        <intercept-url pattern="/login" access="permitAll"/>
        <intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>

        <form-login login-page="/login"
                login-processing-url="/login_check"
                username-parameter="username"
                password-parameter="password"
                authentication-failure-url="/login?error"
                default-target-url="/home" />

        <logout logout-url="/logout"
                logout-success-url="/login?logout" />

        <csrf disabled="true"/>
    </http>

    <authentication-manager>
        <authentication-provider ref="authenticationProvider"/>
        <authentication-provider>
            <user-service>
                <user name="1" password="1" authorities="ROLE_USER"/>
            </user-service>
        </authentication-provider>
</beans:beans>

以下是對上述配置檔案中配置項的解釋說明

  1. login-page="/login" , "/login"頁面是用來展示登入表單的頁面。
  2. login-processing-url="/login_check","/login_check"是用來form表單action所指向的路由,用來標識spring進行登入驗證時所呼叫的連結。
  3. username-parameter="username" 指定了表單中提交使用者名稱所使用input標籤的name。
  4. password-parameter 同上,用來指定提交密碼的input標籤的name
  5. authentication-failure-url="/login?error" 用來說明登入驗證失敗時所跳轉到的連結。
  6. default-target-url="/" 用來標識登入成功後預設跳轉到的連結。
  7. logout-url="/logout" 用來標識進行登出時所需要呼叫的連結
  8. logout-success-url="login?logout" 用來標識登出賬號成功後所跳轉到的連結
  9. <csrf disabled="true"/> 用來標識禁用csrf保護,有關csrf可以查詢其他資料,在這裡不做解釋說明。
  10. <intercept-url pattern="/login" access="permitAll"/> 這條語句用來標識哪些資源允許有哪些許可權的人訪問。
  11. <authentication-manager> 用來宣告驗證登入資訊的資源,這裡展示了兩種,一種是在xml檔案中顯式的宣告<user-service> 來生成登入使用者資訊。另外是使用類來實現AuthenticationProvider 介面並在xml中用<authentication-provider ref="aquariusAdminAuthenticationProvider"/>引用。

3、Login Pages

<#import "/spring.ftl" as spring />

<!-- login.ftl -->
<html>
<head>
</head>
<body>
<div class="mainlogin">
    <form id="login" name="login" action="<@spring.url '/login_check' />" method="POST">
    <#if msg??><p class="error-msg">${msg}</p></#if>
        <p><label>使用者名稱:</label><input name="username" type="text" class="txt" autofocus></p>
        <p><label>密碼:</label><input name="password" type="text" class="txt wid1"></p>
        <input type="submit" id="login_btn" name="submit">登入</input>
    </form>
</div>
</body>
</html>

注意使用freemarker需要引用spring.ftl檔案來進行form表單action的定義。

<!-- home.ftl -->
<html>
<body>
    <h1>Title : ${title}</h1>
    <h1>Message : ${message}</>
</body>
</html>

很簡單的home頁面

4、Spring MVC Controller

package com.lightafire.web.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class HelloController {

    @RequestMapping(value = { "/home" }, method = RequestMethod.GET)
    public ModelAndView welcomePage(Model model) {

        ModelAndView model = new ModelAndView();
        model.addAttribute("title", "Spring Security Custom Login Form");
        model.addAttribute("message", "This is welcome page!");
        return "/home";

    }

    //Spring Security see this :
    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public ModelAndView login(
        @RequestParam(value = "error", required = false) String error,
        @RequestParam(value = "logout", required = false) String logout) {

        ModelAndView model = new ModelAndView();
        if (error != null) {
            model.addAttribute("error", "Invalid username and password!");
        }

        if (logout != null) {
            model.addAttribute("msg", "You've been logged out successfully.");
        }

        return "/login";

    }

}

到這裡全部設定就已經完成了,執行專案訪問/login即可開啟登入頁面,輸入賬號,密碼usernmae:1,password:1即可登入。

5、使用資料庫或其他資料來源進行登入驗證

需要實現之前提到的<authentication-provider ref="authenticationProvider"/>

@Component("authenticationProvider")
public class authenticationProvider implements AuthenticationProvider {

    @Override
    public boolean supports(Class<?> authentication) {
        return true;
    }

    @Override
    public Authentication authenticate(Authentication arg0) throws AuthenticationException {
        // 獲取使用者名稱
        String username = arg0.getName();

        // 獲取密碼
        String password = arg0.getCredentials().toString();

        User user;
        // 嘗試提取使用者資訊,在這裡通過不同方式獲取登入使用者的相關資訊並賦值給user!!!

        // 驗證密碼
        bool valid = user.password == password;

        // 設定許可權
        if (valid) {
            List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
            SimpleGrantedAuthority authority = new SimpleGrantedAuthority(ROLE_USER);
            authorities.add(authority);
            UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(username, password, authorities);
            auth.setDetails("login user.");
            return auth;
        } else {
            // do something when valid failed. 可以拋異常或是進行註冊再return之類的。
        }
    }


}

參考