1. 程式人生 > >(二)如何使用spring-security來實現使用者的登入許可權功能?(配合使用資料庫的方式)

(二)如何使用spring-security來實現使用者的登入許可權功能?(配合使用資料庫的方式)

如何使用spring-security來實現使用者的登入功能之配合使用資料庫的方式

這個圖大家先熟悉一下簡單的過一遍,等把步驟都寫完之後,後面會總結
這裡寫圖片描述

(一)使用spring-security之前需要做的準備(基於springMVC和dubbo的專案)

這裡寫圖片描述
1. 需要先在maven中pom檔案中引入需要的spring-security的依賴

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
>
<modelVersion>4.0.0</modelVersion> <parent> <groupId>com.pinyougou</groupId> <artifactId>pinyougou-parent</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <artifactId>pinyougou-shop-web</artifactId> <packaging
>
war</packaging> <dependencies> <!-- Spring --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId
>
<artifactId>spring-beans</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jms</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> </dependency> <!-- dubbo相關 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> </dependency> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> </dependency> <dependency> <groupId>com.github.sgroschupf</groupId> <artifactId>zkclient</artifactId> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> </dependency> <dependency> <groupId>javassist</groupId> <artifactId>javassist</artifactId> </dependency> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <scope>provided</scope> </dependency> <!-- 這個是使用SpirngSecurity的安全登入框架的依賴 --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> </dependency> <dependency> <groupId>com.pinyougou</groupId> <artifactId>pinyougou-sellergoods-interface</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <!-- 指定埠 --> <port>9102</port> <!-- 請求路徑 --> <path>/</path> </configuration> </plugin> </plugins> </build> </project>

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">  
   <!-- 解決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>   

  <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>
  <!-- 監聽整個專案的作用 -->
   <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>
    <!-- 這個是配置的spring-security過濾鏈,而且這個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>  

  <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>

</web-app>

(二)這一部其實就是在第(一)大步的基礎上,配置spring-security中最重要的一步,這裡單獨作為一大步來進行解釋

(1)先進行配置對靜態的資源進行放行,可根據具體的業務進行特別的放行
(2)再去配置頁面的攔截規則,配合著什麼樣的角色配什麼樣的許可權(這個可以根據自己的業務來)
(3)配置認證管理器,也就是authentication-manager這個類,他的作用就是用來管理你所有的不同角色的使用者

  1. 在這個裡面還可以進行注入對使用者的密碼進行加密的BCrypt方式(可以自行去了解一下)
  2. 如果你想實現使用者在設定密碼的時候就進行加密,就直接定義加密物件,然後把使用者設定的密碼進行加密setter到資料庫中,在認證管理器的時候,你只需要給認證管理器提供這個password-encoder引數,spring-security會幫我們自動解密
  3. 這個就是我使用的時候`
//註冊使用者的時候,使用者自己新增設定密碼的時候進行加密,然後解密的時候你配置好滴(2)步就不用管了
@RequestMapping("/add")
    public Result add(@RequestBody TbSeller seller){
        //對新增的商鋪老闆的密碼進行加密,使用Bcrypt的加密方式
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String password = passwordEncoder.encode(seller.getPassword());
        seller.setPassword(password);

        try {
            sellerService.add(seller);
            return new Result(true, "增加成功");
        } catch (Exception e) {
            e.printStackTrace();
            return new Result(false, "增加失敗");
        }
    }`

這個是service層的介面和實現類

package com.pinyougou.sellergoods.service;
import java.util.List;
import com.pinyougou.pojo.TbSeller;

import entity.PageResult;
/**
 * 服務層介面
 * @author Administrator
 *
 */
public interface SellerService {

    /**
     * 根據ID獲取實體
     * @param id
     * @return
     */
    public TbSeller findOne(String id);
    }

實現類:

/**
 * 服務實現層
 * @author Administrator
 *
 */
@Service
public class SellerServiceImpl implements SellerService {

        /**
     * 根據ID獲取實體
     * @param id
     * @return
     */
    @Override
    public TbSeller findOne(String id){
        return sellerMapper.selectByPrimaryKey(id);
    }
}

查詢資料庫的mappering檔案。這裡就不展示了

4、還需要在spring-security中注入解密bean類
(4)然後你需要去自定義一個類,這個類的作用就是從資料庫中拿資料跟使用者輸入的密碼進行對比(但是對比這一步不需要我們做,直接交給spring-security來做)

package com.pinyougou.service;

import java.util.ArrayList;
import java.util.List;

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;

import com.pinyougou.pojo.TbSeller;
import com.pinyougou.sellergoods.service.SellerService;

/**認證類
 * @author user
 * 這個是專門用來動態從資料庫中取資料進行和使用者輸入的賬號和密碼進行比對的
 */
public class UserDetailsServiceImpl implements UserDetailsService {

    //新增一個set方法,這裡需要使用配置的方式是通過dubbo把另外的一個微服務的service工程給注入進來
    private SellerService sellerService;

    public void setSellerService(SellerService sellerService) {
        this.sellerService = sellerService;
    }


    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //這個集合中裝的是你的不同角色的許可權分組,也就是構建一個角色列表
        List<GrantedAuthority> grantAuths = new ArrayList<GrantedAuthority>();
        //因為GrantedAuthority這個是一個介面,不能直接新增,所以需要new一個SimpleGrantedAuthority的構造器
        grantAuths.add(new SimpleGrantedAuthority("ROLE_SELLER"));
        //然後開始從資料庫中去拿到資料,這裡就是使用了dubbo和zookeeper來實現之間的呼叫
        TbSeller tbSeller = sellerService.findOne(username);
        //先判斷是不是查詢到了資料
        if (tbSeller!=null) {
            //然後還需要判斷若果店鋪的稽核狀態是不是通過的狀態為“1”的才可以登入
            if (tbSeller.getStatus().equals("1")) {
                //表示可以訪問的grantAuths
                return new User(username, tbSeller.getPassword(), grantAuths);
            }else {
                return null;
            }
        }else{
            return null;
        }
    }

}

(5)如果你有用到dubbo的話,由於你的 controller層和service層是分開的兩個不同的專案,但是因為你在你自定義的類中需要呼叫service層來去查詢資料庫,所以你需要使用到dubbo和zookeeper來實現controller和service層的呼叫,如果你麼有用到dubbo可以跳過這一步

最後成果:這是最後都配置好的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)<!-- 頁面的攔截規則    use-expressions:是否啟動SPEL表示式 預設是true -->
    <http use-expressions="false" >
        <!-- 當前使用者必須有ROLE_USER的角色 才可以訪問根目錄及所屬子目錄的資源 -->
        <intercept-url pattern="/**" access="ROLE_SELLER"/>
        <!-- 開啟表單登陸功能 -->
        <!-- default-target-url:這個表示登入成功預設跳轉到的頁面 login-page:這個表示指定的表單進行登入,不用spring-security提供的 -->
        <form-login  login-page="/shoplogin.html" default-target-url="/admin/index.html" authentication-failure-url="/pinyougou-shop-web/login.html" always-use-default-target="true"/>
        <csrf disabled="true"/>
        <headers>
            <frame-options policy="SAMEORIGIN"/>
        </headers>
        <!-- 這個是當你點選退出時候,spring-security會自動幫我們清除掉當前登入的資訊和session -->
        <logout/>
    </http>


    (3)<!-- 認證管理器 -->
    <authentication-manager>
        <authentication-provider user-service-ref="UserDetailsService">
        <!-- 這個user-service其實就是相當於是你的使用者源,現在改為從資料庫中拿到,
        就必須得經過UserDetailsServiceImpl.java這個我們自定義的類 
        而且這個類必須需要實現UserDetailsService這個介面,下面會先把這個自定義的類注入進來-->
            <!-- <user-service>
                <user name="admin" password="123456" authorities="ROLE_ADMIN"/>
                <user name="sunwukong" password="dasheng" authorities="ROLE_ADMIN"/>
                <user name="wangwei" password="123456" authorities="ROLE_ADMIN"/>
            </user-service> -->
        <!-- 因為在使用者新增的時候已經用Bcrypt加密了密碼,這裡需要使用spring-security來提供對應的方法來進行解密 -->
        <password-encoder ref="bcryptEncoder"></password-encoder>
        </authentication-provider>  
    </authentication-manager>

    <!-- 這個是注入認證類,也就是你自定義的那個實現 UserDetailsService這個介面的類-->
    <beans:bean id="UserDetailsService" class="com.pinyougou.service.UserDetailsServiceImpl">
        <beans:property name="sellerService" ref="sellerService"></beans:property>

    </beans:bean>

    (5)<!-- 因為在使用遠端微服務的時候需要用到service層的服務工程,所以這裡需要吧service層的服務工程通過dubbo來引入進來
    1.需要先在認證類中加入一個屬性
     -->
     <!-- 引入dubbo服務:1、需要把dubbo有關的約束標頭檔案也要加進來  2.然後把介面相對路徑加上 3.把認證管理類的name給id的屬性-->
    <dubbo:application name="pinyougou-shop-web" />
    <dubbo:registry address="zookeeper://192.168.25.132:2181"/>
    <!-- 這個可以看成是一個bean為sellerService的一個類 -->
    <dubbo:reference id="sellerService" interface="com.pinyougou.sellergoods.service.SellerService"></dubbo:reference>

    <!-- 這裡需要加上從認證管理器中加入的解密bean類 -->
    <beans:bean id="bcryptEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"></beans:bean>

</beans:beans>