Spring-security框架
阿新 • • 發佈:2018-12-22
spring-security框架
1. 概述 spring-security一個能夠為基於Spring的企業應用系統提供宣告式的安全訪問控制解決方式的安全框架 簡單的說就是一個常用於後臺控制權限的框架 主要分為:使用者認證,使用者授權兩部分 2. 快速入門 1. 入門準備 1.1 匯入依賴jar包 spring-security-web spring-security-config spring-security-taglibs(在jsp中引入可以在jsp頁面進行許可權認證並對頁面進行限制) spring-security-core 1.2 在web.xml中建立filter以及listener * listener與context-param是為了在web專案執行的時候載入spring-security的配置檔案,交給spring管理物件 <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-security.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> * filter是為了攔截url,可以進行後續的使用者認證以及使用者許可權管理 * 特別注意: springSecurityFilterChain這個名字不能更改. 因為原始碼中在載入時名字寫死了是這個 <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> 1.3 在spring-security.xml中配置核心檔案 <?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"> <!--下面三個註解是配置後可以在controller上加來控制不同角色的訪問許可權--> <!--在spring-security.xml中開啟jsr250的註解支援,使用這個註解需要匯入依賴--> <!--<security:global-method-security jsr250-annotations="enabled"/>--> <!--在spring-security.xml中開啟自帶表示式的註解--> <!--<security:global-method-security pre-post-annotations="enabled"/>--> <!--開啟@Secured註解--> <security:global-method-security secured-annotations="enabled"/> <!-- 配置不攔截的資源 --> <security:http pattern="/login.jsp" security="none"/> <security:http pattern="/failer.jsp" security="none"/> <security:http pattern="/css/**" security="none"/> <security:http pattern="/img/**" security="none"/> <security:http pattern="/plugins/**" security="none"/> <!-- 配置具體的規則 auto-config="true" 不用自己編寫登入的頁面,框架提供預設登入頁面 use-expressions="false" 是否使用SPEL表示式,當使用自帶表示式時候,可以設定為true,access寫為hasRole('ROLE_USER') 可以使用||或者&& --> <security:http auto-config="true" use-expressions="false"> <!-- 配置具體的攔截的規則 pattern="請求路徑的規則" access="訪問系統的人,必須有ROLE_USER的角色" --> <security:intercept-url pattern="/**" access="ROLE_USER,ROLE_ADMIN"/> <!-- 定義跳轉的具體的頁面 login-processing-url為登入時候攔截的路徑,要與form表單中的action相同 default-target-url 預設許可權認證通過時候的跳轉頁面 --> <security:form-login login-page="/login.jsp" login-processing-url="/login.do" default-target-url="/index.jsp" authentication-failure-url="/failer.jsp" /> <!-- 關閉跨域請求 --> <security:csrf disabled="true"/> <!-- 退出的相關的方法,以及退出到的頁面 --> <security:logout invalidate-session="true" logout-url="/logout.do" logout-success-url="/login.jsp" /> </security:http> <!-- 切換成資料庫中的使用者名稱和密碼 --> <security:authentication-manager> <security:authentication-provider user-service-ref="userService"> <!-- 配置加密的方式,當資料庫中存放的是明文的時候,不要加,並且驗證時候在密碼前加 {noop} --> <security:password-encoder ref="passwordEncoder"/> </security:authentication-provider> </security:authentication-manager> <!-- 配置加密類 --> <bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/> <!-- 提供了入門的方式,在記憶體中存入使用者名稱和密碼 ,而通常來說,這些應該放置在資料庫中 <security:authentication-manager> <security:authentication-provider> <security:user-service> <security:user name="admin" password="{noop}admin" authorities="ROLE_USER"/> </security:user-service> </security:authentication-provider> </security:authentication-manager> --> <!--當使用自帶表示式的註解的時候,開啟對錶達式的支援,或者配置一個下面的bean--> <bean id="webexpressionHandler" class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler"/> </beans> 2. 配置完畢後,執行專案. spring-security會攔截病跳轉到一個驗證的頁面,當配置了登陸介面時,會跳轉到自定義的頁面.輸入正確的username與password時即可 3. 部分詳解 1. 自定義service實現驗證步驟 spring-security定義了一系列的介面,並且代替了mvc中的controller,我們只需實現service層以及dao層的程式碼即可 1.1 service層的實現 * 定義一個介面 extends UserDetailsService ps:為了擴充套件性,所以先使用介面整合UserDetailsService * 實現自定義的介面並重寫loadUserByUsername(String username)方法 public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { //查詢出一個userInfo UserInfo userInfo = null; try { userInfo = userDao.findByUsername(username); } catch (Exception e) { e.printStackTrace(); } //將自己的物件封裝成為UserDetails //User是UserDetails的一個實現類 //不對userinfo中的status進行驗證 //User user = new User(userInfo.getUsername(),"{noop}"+userInfo.getPassword(),getAuthorities(userInfo.getRoles())); //對userinfo中的status進行驗證未加密 //User user = new User(userInfo.getUsername(),"{noop}"+userInfo.getPassword(),userInfo.getStatus()==1?true:false, //加密後的不用加noop User user = new User(userInfo.getUsername(),userInfo.getPassword(),userInfo.getStatus()==1?true:false, true,true,true,getAuthorities(userInfo.getRoles())); return user; } public List<SimpleGrantedAuthority> getAuthorities(List<Role> roles){ List<SimpleGrantedAuthority> list = new ArrayList<SimpleGrantedAuthority>(); for (Role role : roles) { list.add(new SimpleGrantedAuthority("ROLE_"+role.getRoleName())); } return list; } 2.伺服器端方法級許可權控制 * 開啟註解 配置檔案 <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。 * jsr250註解 @RolesAllowed表示訪問對應方法時所應該具有的角色 示例: @RolesAllowed({"USER", "ADMIN"}) 該方法只要具有"USER", "ADMIN"任意一種許可權就可以訪問。 這裡可以省略字首ROLE_,實際的許可權可能是ROLE_ADMIN @PermitAll表示允許所有的角色進行訪問,也就是說不進行許可權控制 @DenyAll是和PermitAll相反的,表示無論什麼角色都不能訪問 常用寫法: @RolesAllowed("ADMIN") * 支援表示式的註解 * 表示式註解需要開啟表示式的支援 <!--當使用自帶表示式的註解的時候,開啟對錶達式的支援,或者配置一個下面的bean--> <bean id="webexpressionHandler" class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler"/> @PreAuthorize 在方法呼叫之前,基於表示式的計算結果來限制對方法的訪問 示例: @PreAuthorize("#userId == authentication.principal.userId or hasAuthority(‘ADMIN’)") void changePassword(@P("userId") long userId ){... } 這裡表示在changePassword方法執行之前,判斷方法引數userId的值是否等於principal中儲存的當前使用者的userId, 或者當前使用者是否具有ROLE_ADMIN許可權,兩種符合其一,就可以訪問該方法。 @PostAuthorize 允許方法呼叫,但是如果表示式計算結果為false,將丟擲一個安全性異常 示例: @PostAuthorize User getUser("returnObject.userId == authentication.principal.userId or hasPermission(returnObject, 'ADMIN')"); @PostFilter 允許方法呼叫,但必須按照表達式來過濾方法的結果 @PreFilter 允許方法呼叫,但必須在進入方法之前過濾輸入值 Authentication可以簡單理解為: 儲存的認證物件 Principle 可以簡單理解為: 在認證物件中儲存的使用者物件. 常用寫法: @PreAuthorize("authentication.principal.username == 'tom'") //使用者名稱是否為tom @PreAuthorize(hasRole('ROLE_ADMIN')")//使用者是否具有ROLE_ADMIN角色,這裡的ROLE_不能省略 * @Secured註解 @Secured註解標註的方法進行許可權控制的支援,其值預設為disabled 常用寫法: @Secured("ROLE_USER") public Account readAccount(Long id); 3.頁面許可權標籤 * 先引入taglib <%@taglib prefix="security" uri="http://www.springframework.org/security/tags" %> * 在jsp中我們可以使用以下三種標籤來控制權限 authentication <security:authentication property="" htmlEscape="" scope="" var=""/> 注意property=""中的值,多寫為 principal.username property: 只允許指定Authentication所擁有的屬性,可以進行屬性的級聯獲取,如principal.username 不允許直接通過方法進行呼叫 htmlEscape:表示是否需要將html進行轉義。預設為true。 scope:與var屬性一起使用,用於指定存放獲取的結果的屬性名的作用範圍,預設我pageContext。Jsp中擁 有的作用範圍都進行進行指定 var: 用於指定一個屬性名,這樣當獲取到了authentication的相關資訊後會將其以var指定的屬性名進行存 放,預設是存放在pageConext中 常用寫法: <security:authentication property="principal.username"/> authorize <security:authorize access="" method="" url="" var=""></security:authorize> access: 需要使用表示式來判斷許可權,當表示式的返回結果為true時表示擁有對應的許可權 method:method屬性是配合url屬性一起使用的,表示使用者應當具有指定url指定method訪問的許可權, method的預設值為GET,可選值為http請求的7種方法 url:url表示如果使用者擁有訪問指定url的許可權即表示可以顯示authorize標籤包含的內容 var:用於指定將許可權鑑定的結果存放在pageContext的哪個屬性中 常用寫法: <security:authorize access="hasRole('ADMIN')"></security:authorize> accesscontrollist accesscontrollist標籤是用於鑑定ACL許可權的。其一共定義了三個屬性:hasPermission、domainObject和var, 其中前兩個是必須指定的 <security:accesscontrollist hasPermission="" domainObject="" var=""></security:accesscontrollist> hasPermission:hasPermission屬性用於指定以逗號分隔的許可權列表 domainObject:domainObject用於指定對應的域物件 var:var則是用以將鑑定的結果以指定的屬性名存入pageContext中,以供同一頁面的其它地方使用