1. 程式人生 > >spring security4 詳細配置

spring security4 詳細配置

在使用Spring Security之前首先要有個spring的web專案,這裡不再多說。

第一步:新增spring security依賴

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-web</artifactId>
    <version>4.0.2.RELEASE</version>
</dependency>
<dependency
>
<groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>4.0.2.RELEASE</version> </dependency>

第二步:新增spring security 過濾器

<filter>
    <filter-name>springSecurityFilterChain</filter-name
>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>

第三步:配置security的配置檔案

這裡是寫死的兩個使用者名稱密碼,下面註釋掉的是從資料庫取資料驗證的

<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 use-expressions="false">
        <!-- 登入頁面不需要控制權限 -->
        <intercept-url pattern="/login.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
        <!-- 訪問其他所有頁面都需要有USER許可權 -->
        <intercept-url pattern="/**" access="ROLE_USER" />
        <!-- 配置登入頁面地址login-page、登入失敗後的跳轉地址authentication-failure-url -->
        <form-login login-page='/login.jsp' authentication-failure-url='/login.jsp?error' default-target-url="/index.jsp" />
        <!-- 登出功能 -->
        <logout />
        <csrf disabled="true" />

        <!-- 指定自定義過濾器 -->
        <custom-filter ref="authenticationFilter" before="FORM_LOGIN_FILTER" />

    </http>


    <!-- 自定義過濾器 -->
    <beans:bean id="authenticationFilter" class="com.snow.security4.controller.TestLoginFilter">
        <beans:property name="filterProcessesUrl" value="/login" />
        <beans:property name="authenticationManager" ref="authenticationManager" />
    </beans:bean>



    <authentication-manager alias="authenticationManager">
        <authentication-provider>
            <user-service>
                <!-- 這裡建立兩個使用者,可以通過使用者名稱密碼登入 -->
                <user name="jimi" password="jimispassword" authorities="ROLE_USER, ROLE_ADMIN" />
                <user name="bob" password="bobspassword" authorities="ROLE_USER" />
            </user-service>
        </authentication-provider>
    </authentication-manager>


 <!-- 配置資料來源 -->
    <beans:bean id="dataSource"
          class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <beans:property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <beans:property name="url" value="jdbc:mysql://localhost:3306/CTB?serverTimezone=GMT" />
        <beans:property name="username" value="mzh" />
        <beans:property name="password" value="mzh" />
    </beans:bean>

</beans:beans>

經過上面的配置,啟動伺服器,用瀏覽器開啟這個Web應用的任意一個頁面,都會跳轉到一個登入頁,這個登入頁面是Spring Security自動生成的。

這裡寫圖片描述

輸入寫死的那倆使用者名稱密碼即可登入成功。

TestLoginFilter類是個過濾器,如上配置,實在每次spring security做驗證之前都會先經過,這個過濾器。也可以改成after,就是驗證之後經過。

package com.snow.security4.controller;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Created by mazhenhua on 2017/3/20.
 */
public class TestLoginFilter extends UsernamePasswordAuthenticationFilter {


    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {

        System.out.println("就是你了");

        return super.attemptAuthentication(request, response);
    }
}

第四步:連資料庫做驗證

一個比較簡單的方法是:

 <authentication-manager>
        <authentication-provider user-service-ref='userDetailsService' />
    </authentication-manager>
    <beans:bean id="userDetailsService" class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
        <beans:property name="dataSource" ref="dataSource"/>
        <beans:property name="usersByUsernameQuery" value="SELECT username, password, true FROM ctb.user_info WHERE username = ?" />
        <beans:property name="authoritiesByUsernameQuery" value="SELECT username, usertype true FROM ctb.user_info WHERE username = ?;" />
    </beans:bean>

直接把讀密碼和使用者民許可權的sql,丟進來,會直接讀的,

複雜一點的驗證,需要實現一個介面org.springframework.security.core.userdetails.UserDetailsService

public class UserDetailsServiceImpl implements UserDetailsService {

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 以下可以替換成用其他方式獲取使用者資訊
        if(username.equals("xxg")) {
            Collection<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
            SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER"); 
            auths.add(authority);
            User user = new User(username, "123456", auths);
            return user;
        } else {
            throw new UsernameNotFoundException("使用者不存在");
        }
    }
}

然後再配置檔案中配

<authentication-manager>
    <authentication-provider user-service-ref='userDetailsService' />
</authentication-manager>
<beans:bean id="userDetailsService" class="com.snow.security4.controller.UserDetailsServiceImpl" />

第五步:密碼加密

明文儲存密碼通常是不安全的,在Spring Security中可以配置密碼的加密方法。下面以MD5加密密碼為例。

針對密碼加密,Spring Security提供了org.springframework.security.crypto.password.PasswordEncoder介面。我們需要實現PasswordEncoder介面,實現我們自定義的加密方法,這樣Spring Security在接收到使用者登入請求後,會呼叫這個實現類,從而判斷密碼是否正確:

public class PasswordEncoderImpl implements PasswordEncoder {

    @Override
    public String encode(CharSequence rawPassword) {
        try {
            // MD5加密密碼
            return DigestUtils.md5DigestAsHex(rawPassword.toString().getBytes("UTF-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {
        return encode(rawPassword).equals(encodedPassword);
    }
}

配置檔案:

<authentication-manager>
    <authentication-provider>
        <password-encoder ref="passwordEncoder" />
    </authentication-provider>
</authentication-manager>
<beans:bean id="passwordEncoder" class="com.snow.security4.controller.PasswordEncoderImpl" />

第六步:Remember Me

目前很多網站登入時都有“記住我”、“下次自動登入”這樣的chechbox,使用者登入成功後下次再訪問網站就不需要重複登入,對使用者來說非常方便。這個功能在Spring Security中實現起來非常簡單。

首先,你需要在html上寫一個checkbox,name為 remember-me

<input type="checkbox" id="keep-login" name="remember-me"><label for="keep-login">Remember Me</label>

然後在Spring Security配置檔案中加入:

<http use-expressions="false">
    // 如果之前配置http標籤,這裡只將remember-me放進去就好了
    <remember-me />
</http>

預設的Remember Me有效時間時14天,還可以通過token-validity-seconds屬性自定義有效時長(單位:秒)

第七步:配置不受Spring Security管理的URL

如果Web應用中有某些URL不需要被Spring Security管理,例如一些靜態檔案,或者無需登入即可檢視的頁面,可以對這些URL配置security=”none”:

<http pattern="/resources/css/**" security="none"/>
<http pattern="/resources/images/**" security="none"/>
<http pattern="/resources/js/**" security="none"/>

第八步:禁用CSRF防禦

Spring Security預設啟用CSRF防禦,要求每個POST請求都要都要帶上CSRF token引數,如果感覺比較麻煩或者網站安全性要求不高,可以配置禁用:

<http use-expressions="false">
    // 如果之前配置http標籤,這裡只將remember-me放進去就好了
    <csrf disabled="true" />
</http>

第九步:獲取登入使用者資訊

// 獲取使用者名稱
httpServletRequest.getRemoteUser();  // Servlet標準,推薦使用
SecurityContextHolder.getContext().getAuthentication().getName();

// 獲取使用者ROLE:
SecurityContextHolder.getContext().getAuthentication().getAuthorities();

// 判斷使用者是否擁有ROLE:
httpServletRequest.isUserInRole("ADMIN");