SpringSecurity入門

導語

互聯網已經成爲了我們生活一部分,但是安全問題頻發,身份認證變得更爲複雜。如何讓這一部分更安全?如何讓這一部分的身份驗證變得更簡單?下面將介紹Spring全家桶中的安全框架SpringSecurity快速入門及使用,來解決身份驗證問題.
springsecurity是一個能夠爲基於Spring的企業應用系統提供聲明式的安全訪問控制解決方案的安全框架。它提供了一組可以在Spring應用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反轉Inversion of Control ,DI:Dependency Injection 依賴注入)和AOP(面向切面編程)功能,爲應用系統提供聲明式的安全訪問控制功能,減少了爲企業系統安全控制編寫大量重複代碼的工作.下面使用實現一個springsecurity案例

創建maven工程(war包) 導入pom依賴
<!--Spring和SpringSecurity依賴-->
    <dependencies>
        <!--springmvc-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.3.12.RELEASE</version>
        </dependency>
    
        <!-- spring -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jms</artifactId>
            <version>4.3.12.RELEASE</version>
        </dependency>
    
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.3.12.RELEASE</version>
        </dependency>
    
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.12.RELEASE</version>
        </dependency>
    
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>4.3.12.RELEASE</version>
        </dependency>
    
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>4.3.12.RELEASE</version>
        </dependency>
    
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>4.3.12.RELEASE</version>
        </dependency>
    
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.8.6</version>
        </dependency>
    
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.6</version>
        </dependency>
    
        <!--SpringSecurity相關依賴-->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-cas</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>
    
        <!-- MySql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.45</version>
        </dependency>
        
    	<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>  
			<scope>provided</scope>
		</dependency>
		
        <!--數據連接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.13</version>
        </dependency>
    </dependencies>
    <build>
		<plugins>
			<!-- 配置Tomcat插件 -->
			<plugin>
				<groupId>org.apache.tomcat.maven</groupId>
				<artifactId>tomcat7-maven-plugin</artifactId>
				<configuration>
					<port>80</port>
					<!-- http://127.0.0.1:{port}/{path} -->
					<path>/</path>
				</configuration>
			</plugin>
		</plugins>
	</build>
web.xml配置
<!-- 編碼過濾器 -->
  <filter>
    <filter-name>characterEncoding</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
      <param-name>forceEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>

  <filter-mapping>
    <filter-name>characterEncoding</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  <!--//End 編碼過濾器 -->
  
  <!--springsecurity過濾器,做資源權限的攔截和驗證-->
 <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>
  
  <!-- SpringMVC -->
  <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:spring/springmvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>*.html</url-pattern>
  </servlet-mapping>
springmvc.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

	<!-- 包掃描 -->
	<context:component-scan base-package="com.shemuel.controller" />


	<!-- 視圖解析器 -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	    <property name="prefix" value="/WEB-INF/view/" />
	    <property name="suffix" value=".jsp" />
	</bean>

	<!--引入SpringSecurity配置文件-->
	<!--<import resource="spring-security.xml" />-->
	<import resource="spring-security.xml"/>
</beans>
springsecurity.xml 配置(最終配置,後面會講每個部分什麼意思)
<?xml version="1.0" encoding="UTF-8"?>
<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-4.2.xsd ">
	
	
	<!-- 公共資源取消授權攔截 -->
	<!-- <http pattern="/images/**" security="none"/>
	
	<http pattern="/register" security="none"/>
	
	<http pattern="/loginout" security="none"/> -->
	<http pattern="/login.html" security="none"/>
	<http pattern="/login/fail.html?error" security="none"/>
	<!--
	 auto-config表示自動引入springsecurity相關過濾器
	 user-expression屬性表示是否使用 表達式 
	 -->
	<http auto-config="true" use-expressions="true">
    	<!--配置需要過濾哪些頁面,所有帶有user的請求都需要ROLE_ADMIN權限-->
    	<intercept-url pattern="/user/**" access="hasRole('ROLE_ADMIN')" />
    	<form-login login-page="/login.html"
            default-target-url="/user/list.html"
            authentication-failure-url="/login/fail.html?error"
            username-parameter="username"
            password-parameter="password"
            always-use-default-target="true" />
            
        <!--禁用CSRF-->
		<csrf disabled="true"/>
    	
	</http>

	

	<!--授權認證管理器-->
	<authentication-manager>
		<authentication-provider>
		
			<!-- 引用已經配置的加密算法 -->
			<password-encoder ref="encoder"></password-encoder>
			<!-- 對指定數據庫表裏的用戶進行授權認證 -->
			<jdbc-user-service data-source-ref="dataSource" users-by-username-query="select username, password, enabled from users where username=?" />
		</authentication-provider>
	</authentication-manager>
	
	<!-- 數據庫連接池 -->
	<beans:bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
	      destroy-method="close">
	    <beans:property name="url" value="jdbc:mysql://127.0.0.1:3306/security?characterEncoding=utf8" />
	    <beans:property name="username" value="root" />
	    <beans:property name="password" value="root" />
	    <beans:property name="driverClassName" value="com.mysql.jdbc.Driver" />
	    <beans:property name="maxActive" value="10" />
	    <beans:property name="minIdle" value="5" />
	</beans:bean>
	
	<!-- 配置加密算法 -->
	<beans:bean id="encoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
        <beans:constructor-arg name="strength" value="9" /><!-- 加密的密碼長度9 -->
	</beans:bean>
	
</beans:beans>
創建UserController

創建用戶管理的Controller,並加入用戶列表功能

package cn.itcast.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping(value = "/admin/user")
public class UserController {

    /***
     * 用戶管理
     * @return
     */
    @RequestMapping(value = "/list")
    public String list(){
        return "user_list";
    }
}
在/WEB-INF/view/下創建user_list.jsp

爲了演示效果,我們這裏整點假數據展示

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>歡迎來到SpringSecurity的世界</title>
</head>
<body>
    歡迎來到SpringSecurity的世界!<br />
    <table>
        <tr>
            <td>用戶ID</td>
            <td>姓名</td>
            <td>年齡</td>
        </tr>
        <tr>
            <td>1</td>
            <td>張三</td>
            <td>王五</td>
        </tr>
        <tr>
            <td>2</td>
            <td>張三2</td>
            <td>王五</td>
        </tr>
        <tr>
            <td>3</td>
            <td>張三3</td>
            <td>王五</td>
        </tr>
        <tr>
            <td>4</td>
            <td>張三4</td>
            <td>王五</td>
        </tr>
    </table>
</body>
</html>
實現對/user開始的請求攔截

在spring-security.xml中配置攔截信息和授權認證管理器

<http auto-config="true" use-expressions="true">
    <!--所有帶有admin的請求都需要ROLE_ADMIN權限-->
    <intercept-url pattern="/user/**" access="hasRole('ROLE_ADMIN')" />
</http>

<!--授權認證管理器-->
<authentication-manager>
</authentication-manager>

http結點主要配置要攔截的url相關權限規則和處理方案。

auto-config =true:默認會配置多個SpringSecurity相關過濾器,如果不配,就不能正常使用SpringSecurity相關功能。

use-expressions:是否使用SpELl表達式。

,pattern表示要攔截的路徑,可以用通配符表示, * * 表示所有路徑。 access表示對應地址訪問所需的權限,如果use-expressions="false"access="hasRole(‘ROLE_ADMIN’)"這裏的hasRole就可以去掉,我們後面都會設置成false,直接去掉這裏的hasRole方便一點。ROLE_ADMIN表示ADMIN角色,這列角色自定義,可以隨意定義什麼角色,不過注意,這裏必須得大寫。

發佈測試

用tomcat發佈測試,端口號根據你本機情況開放,我這裏端口是80,可以省略
訪問 localhost/user/list.html的時候跳轉到了一個登陸界面,說明攔截配置生效了。
這是springsecurity自帶的登錄頁面,應該是用代碼動態生成的,後面可以改成自己的,

添加授權用戶

接着我們爲上面登陸那裏添加授權用於,允許他們登陸。修改spring-security.xml,在authentication-manager結點下加入如下代碼:

<authentication-provider>
    <!--硬編碼方式提供賬號密碼-->
    <user-service>
        <user name="admin" authorities="ROLE_ADMIN" password="123456" disabled="false" />
    </user-service>
</authentication-provider>

這裏提供了用戶名爲admin 密碼123456 角色爲ROLE_ADMIN的用戶,這裏的角色必須和上面http裏配置的角色保持一致,否則仍然五權限訪問。disabled=false表示不禁用也就是啓用。這時候我們就可以通過該賬號登錄訪問了。
登錄後我們就可以訪問http://localhost/user/list.html了

Spring Security常用配置

基於上面的案例我們繼續學習SpringSecurity相關知識。

取消安全校驗

我們網站中常常會有一些靜態資源或者不需要校驗權限的地址,例如註冊和登錄,我們在webapp下創建一個images文件夾,在裏面放一張圖片1.png。像這些地址或者靜態資源我們如何取消權限校驗呢?在spring-security.xml中加入如下代碼:

<!--不需要過濾的靜態資源和開放連接-->
<http pattern="/images/**" security="none" />
<http pattern="/login.shtml" security="none" />
<http pattern="/login/fail.shtml" security="none" />

這時候 http://localhost/images/1.jpg 就可以訪問了。

自定義登錄頁面

剛纔那個登錄頁面不太美觀,我們能不能讓登錄地址跳轉到指定頁面呢?

首先我們創建一個登錄頁面

/WEB-INF/view/login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>登錄</title></head>
<body>
歡迎登錄!我自己的登錄頁面,後期可進行美化.
<form name='f' action='/login' method='POST'>
    <table>
        <tr>
            <td>用戶名:</td>
            <td><input type='text' name='username' value=''></td>
        </tr>
        <tr>
            <td>密碼:</td>
            <td><input type='password' name='password'/></td>
        </tr>
        <tr>
            <td colspan='2'><input name="submit" type="submit" value="Login"/></td>
        </tr>
    </table>
</form>
</body>
</html>

LoginController

package cn.itcast.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class LoginController {

    /***
     * 登錄
     * @return
     */
    @RequestMapping(value = "/login")
    public String login(){
        return  "login";
    }
}

修改spring-security.xml 在http結點中加入如下代碼:

<!--自定義登錄-->
<form-login login-page="/login.shtml"
            default-target-url="/user/list.shtml"
            authentication-failure-url="/login/fail.html?error"
            username-parameter="username"
            password-parameter="password"
            always-use-default-target="true" />
  • login-page:自定義登錄頁url,默認爲/login
  • default-target-url:默認登錄成功後跳轉的url
  • authentication-failure-url: 登錄失敗後跳轉的url
  • username-parameter:用戶名的請求字段 默認爲userName
  • password-parameter:密碼的請求字段 默認爲password
  • always-use-default-target:是否始終使用默認的地址,即登錄成功後是否總是跳轉到默認地址

再次登錄,發現報403錯誤(如下),是因爲SpringSecurity這裏做了防csrf攻擊校驗,我們禁用csrf校驗即可。

HTTP Status 403 – Forbidden
Type Status Report
Message Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.
Description The server understood the request but refuses to authorize it.
Apache Tomcat/8.5.16

在http結點加入

<!--禁用CSRF-->
<csrf disabled="true" />
登錄錯誤信息處理

在LoginController中加一個錯誤處理方法

/***
 * 登錄失敗
 * @return
 */
@RequestMapping(value = "/login/fail")
public String loginfail(@RequestParam(value = "error",required = false)String error, Model model){
    if(error!=null){
        model.addAttribute("msg","賬號或者密碼不對!");
    }
    return  "login";
}

在登錄的jsp回顯錯誤

<tr>
    <td colspan='2'>
        ${msg}<br />
        <input name="submit" type="submit" value="Login"/>
    </td>
</tr>
數據庫中的用戶賬號密碼登錄

前面我們一直是寫死的用戶賬號和密碼,而真實環境中基本都是從數據庫獲取賬號密碼,這個如何實現?

首先創建一個數據庫叫springsecurity,接着創建兩張表,一張是users表,存放用戶信息,另一張是authorities表,存放用戶角色信息。

  CREATE TABLE `users` (
      `username` varchar(50) NOT NULL,
      `password` varchar(60) NOT NULL,
      `enabled` varchar(50) NOT NULL,
      PRIMARY KEY (`username`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    INSERT INTO users(username,password,enabled)VALUES('itcast','123456','true');
    


    CREATE TABLE `authorities` (
	  `username` varchar(50) NOT NULL,
	  `authority` varchar(50) NOT NULL,
	  PRIMARY KEY (`username`)
	) ENGINE=InnoDB DEFAULT CHARSET=utf8;

	INSERT INTO authorities(username,authority)VALUES('itcast','ROLE_ADMIN');

然後加入在springsecurity.xml中加數據庫連接池配置,上面的最終版配置文件已經有了我這裏就不在寫了. 如果配置了加密,則數據庫裏的密碼也應該爲加密的密碼,否則登錄失敗.
最後登錄成功就能看到如下頁面了
在這裏插入圖片描述

參考:傳智播客教學視頻.
傳智博客官網:http://itcast.cn

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章