Spring Security教程(四):自定義登入頁
阿新 • • 發佈:2018-11-19
在前面的例子中,登陸頁面都是用的Spring Security自己提供的,這明顯不符合實際開發場景,同時也沒有退出和登出按鈕,因此在每次測試的時候都要通過關閉瀏覽器來登出達到清除session的效果。
一、自定義頁面
login.jsp:<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>自定義登陸頁面</title> </head> <body> <div class="error ${param.error == true ? '' : 'hide'}"> 登陸失敗<br> ${sessionScope['SPRING_SECURITY_LAST_EXCEPTION'].message}</div> <form method="post" action="${pageContext.request.contextPath}/j_spring_security_check" style="width:260px; text-align: center"> <fieldset> <legend>登陸</legend> 使用者: <input type="text" name="j_username" style="width: 150px;" value="${sessionScope['SPRING_SECURITY_LAST_USERNAME']}" /><br /> 密碼: <input type="password" name="j_password" style="width: 150px;" /><br /> <input type="checkbox" name="_spring_security_remember_me" />兩週之內不必登陸<br /> <input type="submit" value="登陸" /> <input type="reset" value="重置" /> </fieldset> </form> </body> </html>
說明:
- 特別要注意的是form表單的action是提交登陸資訊的地址,這是security內部定義好的,同時自定義form時,要把form的action設定為/j_spring_security_check。注意這裡要使用絕對路徑,避免登陸頁面存放的頁面可能帶來的問題。
- j_username,輸入登陸名的引數名稱,j_password,輸入密碼的引數名稱,這兩個正常情況下也不會修改。
- _spring_security_remember_me,選擇是否允許自動登入的引數名稱。可以直接把這個引數設定為一個checkbox,無需設定value,Spring Security會自行判斷它是否被選中,這也是security內部提供的,只需要配置,不需要自己實現。
二、配置制定的頁面
配置檔案如下:<?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-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd"> <!-- <http pattern="/login.jsp" security="none"></http> --> <http auto-config="false"> <intercept-url pattern="/login.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY" /> <intercept-url pattern="/adminPage.jsp" access="ROLE_ADMIN" /> <intercept-url pattern="/**" access="ROLE_USER" /> <form-login login-page="/login.jsp" default-target-url="/index.jsp" authentication-failure-url="/login.jsp?error=true" /> <logout invalidate-session="true" logout-success-url="/login.jsp" logout-url="/j_spring_security_logout"/> </http> <!-- 資料來源 --> <beans:bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <!-- 此為c3p0在spring中直接配置datasource c3p0是一個開源的JDBC連線池 --> <beans:property name="driverClass" value="com.mysql.jdbc.Driver" /> <beans:property name="jdbcUrl" value="jdbc:mysql://localhost:3306/springsecuritydemo?useUnicode=true&characterEncoding=UTF-8" /> <beans:property name="user" value="root" /> <beans:property name="password" value="" /> <beans:property name="maxPoolSize" value="50"></beans:property> <beans:property name="minPoolSize" value="10"></beans:property> <beans:property name="initialPoolSize" value="10"></beans:property> <beans:property name="maxIdleTime" value="25000"></beans:property> <beans:property name="acquireIncrement" value="1"></beans:property> <beans:property name="acquireRetryAttempts" value="30"></beans:property> <beans:property name="acquireRetryDelay" value="1000"></beans:property> <beans:property name="testConnectionOnCheckin" value="true"></beans:property> <beans:property name="idleConnectionTestPeriod" value="18000"></beans:property> <beans:property name="checkoutTimeout" value="5000"></beans:property> <beans:property name="automaticTestTable" value="t_c3p0"></beans:property> </beans:bean> <authentication-manager> <authentication-provider> <jdbc-user-service data-source-ref="dataSource" users-by-username-query="select username,password,status as enabled from user where username = ?" authorities-by-username-query="select user.username,role.name from user,role,user_role where user.id=user_role.user_id and user_role.role_id=role.id and user.username=?"/> </authentication-provider> </authentication-manager> </beans:beans>
說明:
- form-login這個標籤是配置登陸頁面的,其中的屬性login-page是配置登陸頁面的,default-target-url配置登陸成功後跳轉到的頁面,authentication-failure-url配置認證失敗後的跳轉頁面。
- 在上面的配置中,登陸頁面肯定是不能攔截的,任何人都應該可以訪問,<intercept-url pattern="/login.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY" />配置表示允許匿名使用者訪問,就是不用身份都可以訪問;還有另一種配置方式:<http pattern="/login.jsp" security="none"></http>,這種配置達到的目的都是一樣的。
- logout這個標籤用來配置退出或者登出,其中的屬性invalidate-session,配置否是要清除session,logout-success-url配置登出成功後的跳轉頁面,logout-url提交退出或者登出的地址,因此我們在配置退出或者登出的時候,只需要將url設定為/j_spring_security_logout即可,這個地址也是security內部實現了的。
- form-login標籤中還有一個特別要注意的屬性use-expressions,如果設定為true,這配置access就要做相應的改變,否則專案啟動的時候會報錯,錯誤如下:
如果use-expressns="true"時,則表示改為 SpEL 表示式。 SpEL 允許使用特定的訪問控制規則表示式語言。與簡單的字串如 ROLE_USER 不同,配置檔案可以指明表示式語言觸發方法呼叫、引用系統屬性、計算機值等等。http標籤中的配置改為如下:
<http auto-config="false" use-expressions="true"> <intercept-url pattern="/login.jsp" access="permitAll" /> <intercept-url pattern="/adminPage.jsp" access="hasRole('ROLE_ADMIN')" /> <intercept-url pattern="/**" access="hasRole('ROLE_USER')" /> <form-login login-page="/login.jsp" default-target-url="/index.jsp" authentication-failure-url="/login.jsp?error=true" /> <logout invalidate-session="true" logout-success-url="/login.jsp" logout-url="/j_spring_security_logout"/> </http>配置檔案中的其他配置在前面幾篇部落格中都有詳細的講解,這裡就不贅述了。
三、其他檔案
index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <h1>this is a user page</h1> <a href="${pageContext.request.contextPath}/j_spring_security_logout">退出登陸</a> </body> </html>
adminPage.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <h1>this is a admin page</h1> <a href="${pageContext.request.contextPath}/j_spring_security_logout">退出登陸</a> </body> </html>
這裡定義了兩個頁面,index.jsp使用者和管理員都可以訪問,adminPage.jsp只有管理員可以訪問,同時兩個頁面都有登出按鈕,登出按鈕提交的地址也就是上面配置檔案中的地址/j_spring_security_logout。
pom.xml和前面的一樣,這裡就不貼了。
四、結果
當輸入普通使用者的使用者名稱和密碼,同時勾選2周不用登陸後,因為adminPage.jsp頁面要有管理員許可權才能訪問,所以普通使用者訪問失敗,index.jsp頁面就可以訪問;這時關閉頁面後,再次訪問資源,因為勾選了2周不用登陸,所以可以成功訪問;但是當點選退出登入後,再次訪問是就會跳轉到登陸頁面,要求登陸才能訪問。
當輸入管理員名和密碼,同時勾選2周不用登陸,驗證成功後,跳轉到index.jsp,同時adminPage.jsp也可以訪問,這時把一個頁面關閉再重新訪問資源時,因為勾選2周不用登陸,所以可以成功訪問;然後登出,這是再訪問資源時,就會跳轉到登陸頁面,要求登陸才能訪問。