天天看點

SSM配置Spring securitySSM配置Spring security1.概念了解2.項目背景3.配置spring security4.成功場景5.使用資料庫資料進行認證6.服務端方法級别權限控制7.頁面權限控制6.友情提示

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

    <!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>
               
    index.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        首頁
    </body>
    </html>
               
    lost.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可能的解決方法
  • 我嘗試了很多遍,最終配置完了,如果沒成功不要急着去搜尋配置的部落格,自己從最開始走一遍,從最簡單的檢驗配置的方法來,有了概念後配置起來就會得心應手