SSM配置Spring security
1.概念了解
- spring security是一個權限控制元件,負責對使用者登入通路的控制,包括登入認證,通路界面的控制等等。
2.項目背景
- 管理工具Maven
- 項目架構SSM
3.配置spring security
3.1 jar包導入
<!--版本鎖定-->
<spring.version>5.0.7.RELEASE</spring.version>
<spring.security.version>5.0.6.RELEASE</spring.security.version>
<!--導入jar坐标-->
<!--spring security -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring.security.version}</version>
</dependency>
<!-- 如果不打算用版本鎖定将${spring.security.version}替換為具體版本即可,
需要注意的是spring security和spring是對應的,是以如果是初學建議直接使用我提供的版本-->
3.2 編寫配置檔案
以下選一個即可,初次學習建議先試用版本1
3.2.1 spring-security.xml
3.2.1.1. spring-security.xml版本1(使用預設界面檢驗配置)
初次使用建議直接粘貼此配置,檢驗配置是否成功
此處配置了登入的使用者名及密碼,分别是
user, user
admin,admin
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
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">
<security:http auto-config="true" use-expressions="false">
<!-- 配置攔截路徑及通行權限 -->
<security:intercept-url pattern="/**" access="ROLE_USER" />
</security:http>
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<!--使用者密碼未加密,添加{noop}-->
<security:user name="user" password="{noop}user" authorities="ROLE_USER" />
<security:user name="admin" password="{noop}admin" authorities="ROLE_ADMIN" />
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
</beans>
3.2.1.2 spring-security.xml 版本2(自定義登入界面)
此時預設你已經能正常運作出預設界面了,使用此配置去配置真實的檔案等等
- 此檔案中的賬戶名和密碼仍然是寫死的,直接在配置檔案裡面讀取-
- 此配置檔案需要你有以下幾個頁面(與WEB-INF同級)
登入界面:login.html(此頁面建議使用下面的内容,直接粘貼,或依照提示編寫)
登入權限不足提示界面:lost.html
登入成功界面:index.html
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
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">
<!-- 配置不過濾的資源(靜态資源及登入相關) -->
<security:http security="none" pattern="/login.html" />
<security:http security="none" pattern="/failer.html" />
<security:http auto-config="true" use-expressions="false">
<!-- 配置攔截路徑及通行權限 -->
<security:intercept-url pattern="/**" access="ROLE_USER" />
<!--
login-page 自定義登陸頁面
authentication-failure-url 使用者權限校驗失敗跳轉頁面,如果資料庫中沒有這個使用者則不會跳轉到這個頁面。
default-target-url 登陸成功跳轉頁面
注:登陸頁面使用者名固定 username,密碼 password,action:login -->
<security:form-login login-page="/login.html" login-processing-url="/login"
username-parameter="username"
password-parameter="password"
authentication-failure-url="/lost.html"
default-target-url="/index.html" authentication-success-forward-url="/index.html"/>
<!-- 登出,
invalidate-session 是否删除session
logout-url:登出處理連結
logout-success- url:登出成功頁面 -->
<security:logout invalidate-session="true" logout-url="/logout" logout-success-url="/login.jsp" />
<!-- 關閉 C S R F,跨伺服器請求,預設是開啟的,關閉 -->
<security:csrf disabled="true" />
</security:http>
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<!--使用者密碼未加密,添加{noop}-->
<security:user name="user" password="{noop}user" authorities="ROLE_USER" />
<security:user name="admin" password="{noop}admin" authorities="ROLE_ADMIN" />
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
</beans>
-
附屬頁面配置
login.html
index.html<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登入界面</title> </head> <body> <form action="login" method="post"> <input type="text" name="username"> <input type="text" name="password"> <input type="reset" value="重置"> <input type="submit" name="submit" value="login"> </form> </body> </html>
lost.html<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> 首頁 </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> 權限不足 </body> </html>
3.2.1.3 spring-security.xml 版本3 (使用者名及密碼來源為資料庫)
-
spring-security.xml 配置
此部分内容需要配合service及資料庫,請看5節
3.2.2 配置檔案,web.xml
- 檔案内容
<!--設定配置檔案的路徑--> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml,classpath:spring-security.xml</param-value> </context-param>
<!-- 權限管理--> <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> <welcome-file-list> <welcome-file>login.jsp</welcome-file> <welcome-file>login.html</welcome-file> <welcome-file>index.html</welcome-file> </welcome-file-list>
4.成功場景
4.1 使用預設配置登入界面
- 使用:user, user,登入成功後會跳轉
- 使用:admin, admin,登入失敗後跳轉提示403,伺服器了解請求但拒絕通路。
- 使用:其它未登記的使用者名和密碼(配置檔案中沒有的),報錯并顯示紅色字型
4.2使用自定義登入界面
- 使用:user, user,登入成功後會跳轉到 index.html
- 使用:admin, admin,登入失敗後跳轉到 lost.html
4.3 使用使用者名及密碼來源于資料庫的
- 此時的使用者名和密碼的配置基于你的需求及設定,到此你應該基本了解security負責的部分及簡單配置。
5.使用資料庫資料進行認證
5.1 spring-security.xml
以下不含所有配置及檔案,隻有大緻思路及部配置設定置檔案,不過基本已經夠了
認證方式userDetail,userDetailService
做法:userService實作UserDetails的接口
-
前提:
資料庫中有user表
username, password,status(目前使用者賬号狀态)
資料庫中有role表roleID, roleName, roleDesc(角色描述)
資料庫中有user_role關聯表含有使用者ID,roleID
- security配置檔案
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:security="http://www.springframework.org/schema/security" 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"> <!-- 配置不過濾的資源 --> <security:http security="none" pattern="/login.html" /> <security:http security="none" pattern="/failer.html" /> <security:http auto-config="true" use-expressions="false"> <!-- 配置攔截路徑及通行權限 --> <security:intercept-url pattern="/**" access="ROLE_USER" /> <!-- login-page 自定義登陸頁面 authentication-failure-url 使用者權限校驗失敗跳轉頁面,如果資料庫中沒有這個使用者則不會跳轉到這個頁面。 default-target-url 登陸成功跳轉頁面 登陸頁面使用者名固定 username,密碼 password,action:login --> <security:form-login login-page="/login.html" login-processing-url="/login" username-parameter="username" password-parameter="password" authentication-failure-url="/lost.html" default-target-url="/index.html" authentication-success-forward-url="/index.html"/> <!-- 登出, invalidate-session 是否删除session logout-url:登出處理連結 logout-success- url:登出成功頁面 --> <security:logout invalidate-session="true" logout-url="/logout" logout-success-url="/login.jsp" /> <!-- 關閉 C S R F,跨伺服器請求,預設是開啟的,關閉 --> <security:csrf disabled="true" /> <!--認證器--> <security:authentication-manager> <!--下面的userService中就實作了對應的方法,--> <security:authentication-provider user-service-ref="userService"> <security:password-encoder ref="passwordEncoder"/> </security:authentication-provider> </security:authentication-manager> </security:http> </beans>
- userService
public interface UserService extends UserDetailsService { //...省略一些其他關于使用者操作的接口 }
//security配置了驗證器之後,在校驗時會自動調用loadUserByUsername,對使用者進行校驗,故我們需要将其實作 @Service("userService") public class UserServiceImpl implements UserService { //...還有其他一些方法,此處省略 @Override public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException { IUser iuser = null; iuser = userDao.findUserByName(name); //注意此處的User不是自定的的XXX.XXX.domain或者XXX.XXX.po下的自定義的類,而是security中含有的User,故,若你的類也稱之為User建議更改為其它名稱如:IUser等。 //下面的"{noop}"未加密時需要标注 //加密後security配置加密後,需要去掉此辨別 User user = new User(iuser.getUsername(),"{noop}"+iuser.getPassword(), iuser.getStatus() == 0?false:true,true,true,true,getAuthority(iuser.getRoles())); return user; } //提供角色組的資訊,一般是從資料庫中查詢到的 private List<SimpleGrantedAuthority> getAuthority(List<Role> roles) { List<SimpleGrantedAuthority> list = new ArrayList<>(); for (Role role: roles){ //此處應該給出目前使用者的角色名稱 list.add(new SimpleGrantedAuthority("ROLE_"+role.getRoleName())); } return list; } }
5.2 配置使用者密碼加密
- spring-security.xml中配置
<security:authentication-manager> <!--下面的userService中就實作了對應的方法,--> <security:authentication-provider user-service-ref="userService"> <!-- 加密--> <security:password-encoder ref="passwordEncoder"/> </security:authentication-provider> </security:authentication-manager> <!-- 配置加密類--> <bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"></bean>
- userServiceImpl中需要去掉對應的{noop}辨別,修改後的java類
@Service("userService") public class UserServiceImpl implements UserService { //...還有其他一些方法,此處省略 @Override public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException { //... //加密後security配置加密後,需要去掉此辨別 User user = new User(iuser.getUsername(),iuser.getPassword(), iuser.getStatus() == 0?false:true,true,true,true,getAuthority(iuser.getRoles())); return user; } //提供角色組的資訊,一般是從資料庫中查詢到的 //...查詢包裝角色資訊函數 }
6.服務端方法級别權限控制
6.1開啟控制注解
<security:global-method-security jsr250-annotations="enabled"/>
<security:global-method-security secured-annotations="enabled"/>
<security:global-method-security pre-post-annotations="disabled"/>
@EnableGlobalMethodSecurity :
Spring Security預設是禁用注解的在繼承WebSecurityConfigurerAdapter的類上加
@EnableGlobalMethodSecurity注解,并在該類中将AuthenticationManager定義為Bean。
6.2JSR-250注解
@RolesAllowed表示通路對應方法時所應該具有的角色
@PermitAll表示允許所有的角色進行通路
@DenyAll 無論什麼角色都不能通路
6.3表達式注解
@PreAuthorize 基于表達式的計算結果來限制對方法的通路
@PostAuthorize 允許方法調用,當表達式計算結果為false,将抛出一個安全性異常
@PostFilter 允許方法調用,但必須按照表達式來過濾方法的結果
@PreFilter 允許方法調用,但必須在進入方法之前過濾輸入值
6.4 @Secured注解
7.頁面權限控制
jsp頁面中使用spring security提供的權限标簽可對頁面顯示與否進行控制
7.1配置及使用
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>version</version>
</dependency>
使用,頁面添加如下标簽
<%@taglib uri="http://www.springframework.org/security/tags" prefix="security"%>
7.2使用标簽
- authentication
- authorize
- accesscontrollist
7.2.1 authentication
代表目前認證對象,可以擷取目前認證對象資訊
-
property: 隻允許指定Authentication所擁有的屬性,可以進行屬性的級聯擷取,如“principle.username”,
不允許直接通過方法進行調用
- htmlEscape:表示是否需要将html進行轉義。預設為true。
- scope:與var屬性一起使用,用于指定存放擷取的結果的屬性名的作用範圍,預設我pageContext。Jsp中擁
有的作用範圍都進行進行指定
- var: 用于指定一個屬性名,這樣當擷取到了authentication的相關資訊後會将其以var指定的屬性名進行存
放,預設是存放在pageConext中
7.2.2 authorize
- access: 需要使用表達式來判斷權限,當表達式的傳回結果為true時表示擁有對應的權限
- method:method屬性是配合url屬性一起使用的,表示使用者應當具有指定url指定method通路的權限,
method的預設值為GET,可選值為http請求的7種方法
- url:url表示如果使用者擁有通路指定url的權限即表示可以顯示authorize标簽包含的内容
- var:用于指定将權限鑒定的結果存放在pageContext的哪個屬性中
7.2.3 accesscontrollist
- 必要:hasPermission、domainObject
6.友情提示
- 如果使用了user的登入Controller請去掉login的注解,我們的配置檔案中預設設定了登入跳轉為login,這在security中是有處理的,若你配置了但沒有提供security需要的資訊,則始終會嘗試錯誤
- 需要明确的概念是你的 user 的 login 和 user 的 logout 都由security控制,不再使用controller
- 若顯示你的URL沒有對應的Mapping可能的解決方法
- 我嘗試了很多遍,最終配置完了,如果沒成功不要急着去搜尋配置的部落格,自己從最開始走一遍,從最簡單的檢驗配置的方法來,有了概念後配置起來就會得心應手