SpringSecurity的簡單使用


  • 導入SpringSecurity坐標

  • 在web.xml中配置過濾器

  • 編寫spring-securiy配置文件

  • 編寫自定義認證提供者

  • 用戶新增時加密密碼

  • 配置頁面的login和logout

  • 獲取登錄用戶的信息


一.SpringSecurity簡介

  Spring Security是一個能夠為基於Spring的企業應用系統提供聲明式的安全訪問控制解決方案的安全框架。它提供了一組可以在Spring應用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反轉Inversion of Control ,DI:Dependency Injection 依賴注入)和AOP(面向切面編程)功能,為應用系統提供聲明式的安全訪問控制功能,減少了為企業系統安全控制編寫大量重復代碼的工作。

如果要對Web資源進行保護,最好的辦法莫過於Filter,要想對方法調用進行保護,最好的辦法莫過於AOP。Spring security對Web資源的保護,就是靠Filter實現的。

二.SpringSecurity的使用

1.導入SpringSecurity的坐標

<!-- SpringSecurity相關坐標 -->
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-web</artifactId>
    <version>4.1.0.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
    <version>4.1.0.RELEASE</version>
</dependency>

2.在web.xml中配置過濾器

<?xml version="1.0" encoding="UTF-8"?>
<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">
    <!-- 1.解決post亂碼 -->
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- 2.配置SpringMVC的前端控制器 -->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 指定加載的配置文件 ,通過參數contextConfigLocation加載-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring/springmvc.xml</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>

    <!-- 3.配置SpringSecurity的過濾器(以一當十) -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring/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>
</web-app>

3.編寫SpringSecurity的配置文件(spring-security.xml)

<?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:dubbo="http://code.alibabatech.com/schema/dubbo"
    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://code.alibabatech.com/schema/dubbo 
                        http://code.alibabatech.com/schema/dubbo/dubbo.xsd
                        http://www.springframework.org/schema/security 
                        http://www.springframework.org/schema/security/spring-security.xsd">
   
    <!-- 1.配置頁面的放行規則(不需要登錄驗證的資源) -->
    <http pattern="/*.html" security="none"></http>
    <http pattern="/css/**" security="none"></http>
    <http pattern="/img/**" security="none"></http>
    <http pattern="/js/**" security="none"></http>
    <http pattern="/plugins/**" security="none"></http>
    <http pattern="/seller/add.do" security="none"></http>

    <!-- 2.頁面的攔截規則 -->
    <http use-expressions="false">
        <!-- 2.1當前用戶必須有ROLE_USER的角色 才可以訪問根目錄及所屬子目錄的資源 -->
        <intercept-url pattern="/**" access="ROLE_USER"/>
        <!-- 2.2表單登陸,默認用戶名和密碼的name屬性為:username和password,也可在這里配置 -->
        <form-login  login-page="/shoplogin.html"
                     default-target-url="/admin/index.html"
                     authentication-failure-url="/shoplogin.html"
                     always-use-default-target="true"/>
        <!-- 2.3關閉跨域攻擊 -->
        <csrf disabled="true"/>

        <!-- 2.4為了解決frame框架訪問問題默認是deny不允許訪問,改成同一域下可以進行訪問-->
        <headers>
            <frame-options policy="SAMEORIGIN"/>
        </headers>
        <!-- 2.5配置登出功能(頁面注銷連接到“/logout"即可完成退出到指定頁面) -->
        <logout logout-success-url="/login.html"></logout>
    </http>
    
    <!-- 3.認證管理器 -->
    <authentication-manager>
        <!-- 3.1認證提供者:這里是寫成固定的,也可以自定義 -->
        <authentication-provider>
            <user-service>
                <!-- 配置當前系統的用戶 authorities該用戶屬於哪個角色:這里寫成固定的 -->
                <user name="admin" password="123456" authorities="ROLE_USER"/>
            </user-service>
        </authentication-provider>
        <!-- 3.1認證提供者:這里是寫成固定的,也可以自定義 -->
        <!-- ======================================================== -->
        <!-- 3.2通過自定義認證提供者,實現動態認證 -->
        <authentication-provider user-service-ref="userDetailService">
            <!-- 認證時,先對用戶輸入的密碼加密再和數據庫的對比 -->
            <password-encoder ref="bcryptEncoder"></password-encoder>
        </authentication-provider>    
        <!-- 3.2通過自定義認證提供者,實現動態認證 -->
    </authentication-manager>
        
    <!-- 4.認證類:配置的方式進行注入 -->
    <beans:bean id="userDetailService" class="cn.dintalk.service.UserDetailsServiceImpl">
        <beans:property name="sellerService" ref="sellerService"></beans:property>
    </beans:bean>
    
    <!-- 5.引用dubbo 服務 -->
    <dubbo:application name="dintalk-shop-web" />
    <dubbo:registry address="zookeeper://192.168.88.130:2181"/>
        <!-- 5.1配置的方式注入sellerService -->
    <dubbo:reference id="sellerService" interface=
                     "cn.dintalk.sellergoods.service.SellerService"></dubbo:reference>
    
    <!-- 6.配置密碼加密方式 -->
    <beans:bean id="bcryptEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"></beans:bean>
</beans:beans>

4.編寫自定義認證提供者(如需自定義)

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
/**
 * 用戶的登錄認證
 * @author Mr.song
 * @date 2019/06/06 12:26
 */
public class UserDetailsServiceImpl implements UserDetailsService {

    /**
     * 提供set方法以注入sellerService
     */
    private SellerService sellerService;
    public void setSellerService(SellerService sellerService) {
        this.sellerService = sellerService;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //1.根據用戶名查詢數據庫
        TbSeller seller = sellerService.findOne(username);
        //2.判斷用戶是否存在
        if (seller != null){
            //3.定義集合,封裝用戶的角色(這里角色少,寫死.也可以從數據庫查詢)
            List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
            grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_USER"));
            if (seller.getStatus().equals("1")){//用戶處於可以登錄的狀態
                return new User(username,seller.getPassword(),grantedAuthorities);
            }
        }
        //3.用戶不存在,認證失敗
        return null;
    }
}

5.用戶新增時加密密碼(如需加密)

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
/**
* 增加
* @param seller
* @return
*/
@RequestMapping("/add")
public Result add(@RequestBody TbSeller seller){
    try {
        //添加時進行密碼的加密,登錄時配置同樣的加密器即可
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String newPws = passwordEncoder.encode(seller.getPassword());
        seller.setPassword(newPws);
        sellerService.add(seller);
        return new Result(true, "增加成功");
    } catch (Exception e) {
        e.printStackTrace();
        return new Result(false, "增加失敗");
    }
}

6.配置頁面的login和logout

<!-- 1.login的配置要點:默認,登錄框的name屬性分別為username和password(也可在配置中修改)
    登錄表單提交方式為post,登錄鏈接為:/login-->
<form method="post" id="loginform" action="/login">
    <input name="username" type="text" placeholder="郵箱/用戶名/手機號">
    <input name="password" type="password" placeholder="請輸入密碼">
    <a onclick="document:loginform.submit()" target="_blank">&nbsp;&nbsp;</a>
</form>

<!-- 2.logout的配置要點:默認,退出鏈接為:/logout即可 -->
<a href="/logout" >注銷</a>

7.獲取登錄用戶的信息

import org.springframework.security.core.context.SecurityContextHolder;
...
/**
 * 獲取用戶登錄名進行展示
 * @return
 */
@RequestMapping("/showName")
public Map showName(){
    //1.從認證處取得登錄信息(除了username還可獲取其他信息)
    String name = SecurityContextHolder.getContext().getAuthentication().getName();
    //2.構建Map並返回
    HashMap<String, String> map = new HashMap<>();
    map.put("name",name);
    return map;
}

 

 

關注微信公眾號,隨時隨地學習


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM