天天看點

Spring Security入門Spring Security

Spring Security

Spring Security 是Spring 項目中用來提供安全認證服務的架構.

  • 認證: 是為使用者建立一個他所聲明的主體, 主體一般指使用者, 裝置或可以在你系統中執行動作的其他系統.
  • 授權: 指的是一個使用者能否在你的應用中執行某個操作, 在到達授權判斷之前, 身份的主體已經由身份驗證過程建立了.

這些概念是通用的, 不是Spring Security特有的, 在身份驗證層面, Spring Security廣泛支援各種身份驗證模式.

入門

導入依賴坐标

<!-- 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>
           

web.xml配置

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                             http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         version="2.5">
  <display-name>Archetype Created Web Application</display-name>

  <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>
    <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>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  
</web-app>
           

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">

    <security:http auto-config="true" use-expressions="false">
        <!--
        intercept-url 定義一個過濾規則 pattern表示對哪些url進行權限控制. access熟悉表示在請求對于的yrl時需要什麼權限
        預設配置時它應該是一個已逗号分隔的角色清單, 請求的使用者隻需擁有其中的一個角色就能成功通路對應的URL
        -->
        <security:intercept-url pattern="/**" access="ROLE_USER"/>

        <!--
        auto-config 配置後, 不需要在配置下面資訊 <security:from-login/>定義登入表單資訊
        <security:http-basic/> <security:logout/>
        -->
    </security:http>

    <security:authentication-manager>
        <security:authentication-provider>
            <security:user-service>
                <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>
           

指定資源不過濾

<!-- 配置不過濾的資源(靜态資源及登入相關) -->
<security:http security="none" pattern="/login.html" />
<security:http security="none" pattern="/failer.html" />
           

指定登入頁面(成功, 失敗, 登出)

<security:http auto-config="true" use-expressions="false" >

    <!-- 配置資料連接配接,表示任意路徑都需要ROLE_USER權限 -->
    <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="/failer.html" default-target-url="/success.html" authentication-success-forward-url="/success.html"/>
    <!--
    登出, invalidate-session 是否删除session logout-url:登出處理連結 logout-success-url:登出成功頁面
    注:登出操作 隻需要連結到 logout即可登出目前使用者
    -->
    <security:logout invalidate-session="true" logout-url="/logout" logout-success-url="/login.jsp" />

    <!-- 關閉CSRF,預設是開啟的 -->
    <security:csrf disabled="true" />
</security:http>
           

UserDetails

UserDetails

是一個接口, 對認證主體進行了規範, 通常使用實作類

User

進行使用

其中

Collection<? extends GrantedAuthority>

代表了角色擁有的權限集合, 其集合繼承了

GrantedAuthority

public interface UserDetails extends AuthenticatedPrincipal, Serializable {
    Collection<? extends GrantedAuthority> getAuthorities();

    String getPassword();

    String getUsername();

    boolean isAccountNonExpired();

    boolean isAccountNonLocked();

    boolean isCredentialsNonExpired();

    boolean isEnabled();

    default String getName() {
        return this.getUsername();
    }
}
           

UserDetallService

IUserService

需要繼承

UserDetailsService

public interface IUserService extends UserDetailsService {
}
           

UserServiceImpl

需要實作

loadUserByUsername

方法, 傳回值為

UserDetails

, 使用實作類

User

傳回

@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
    UserInfo userInfo = null;
    try {
        userInfo = dao.findByUsername(s);
    } catch (Exception e) {
        e.printStackTrace();
    }
    assert userInfo != null;
    //處理自己的使用者對象封裝成UserDetails
    return new User(userInfo.getUsername(), "{noop}" + userInfo.getPassword(), userInfo.getStatus() == 1, true, true, true, getAuthority(userInfo.getRoles()));
}
           

構造

User

實體需要傳入角色的權限集合, 即

Collection<? extends GrantedAuthority>

, 是以提供了一個私有方法來擷取權限的集合, 集合的類型為

SimpleGrantedAuthority

其繼承了

GrantedAuthority

.

/**
 * 傳回一個list集合, 集合中裝入的是角色描述
 * @return list集合
 */
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;
}
           

完整代碼實作:

/**
 * @Author Harlan
 * @Date 2020/9/25
 */
@Service("userService")
@Transactional
public class UserServiceImpl implements IUserService {

    @Autowired
    private IUserDao dao;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        UserInfo userInfo = null;
        try {
            userInfo = dao.findByUsername(s);
        } catch (Exception e) {
            e.printStackTrace();
        }
        assert userInfo != null;
        //處理自己的使用者對象封裝成UserDetails
        return new User(userInfo.getUsername(), "{noop}" + userInfo.getPassword(), userInfo.getStatus() == 1, true, true, true, getAuthority(userInfo.getRoles()));
    }

    /**
     * 傳回一個list集合, 集合中裝入的是角色描述
     * @return list集合
     */
    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;
    }

}