品優購項目記錄:day04

 

今日目標:

        (1)實現 Spring Security 入門 Demo

        (2)完成運營商登錄與安全控制功能

        (3)完成商家入駐

        (4)完成商家審覈

        (5)完成商家系統登錄與安全控制功能

 

 

目錄

1、運營商系統登錄與安全控制

1.1 導入 Spring Security 依賴

1.2 配置文件相關

1.3 登錄後顯示登錄用戶名

1.4 退出登錄

2、商家申請入駐

2.1 前端

2.2 後端

3、商家審覈

3.1 待審覈商家列表

3.2 查看商家詳情

3.3 商家狀態修改

4、商家系統登錄和安全控制

4.1 準備工作

4.2 商家登錄

4.3 BCrypt加密算法

4.4 商家入駐時,進行密碼加密

4.5 商家管理與商家審覈一致,參考商家審覈

5、商家修改資料

5.1 回顯數據到修改資料頁面

5.2 前端

5.2 點擊保存,修改資料(後端部分已由代碼生成器生成)

6、商家修改密碼

6.1 後端

6.2 前端


 

 

1、運營商系統登錄與安全控制

 

 

1.1 導入 Spring Security 依賴

        <!-- spring security -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
        </dependency>

 

 

 

1.2 配置文件相關

(1)web.xml 新增配置

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

 

(2)新增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: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">

	<!-- 以下頁面不被攔截 -->
	<http pattern="/login.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 use-expressions="false">
		<intercept-url pattern="/**" access="ROLE_ADMIN" />
		<form-login login-page="/login.html"  default-target-url="/admin/index.html"
					authentication-failure-url="/login.html" always-use-default-target="true"/>
		<csrf disabled="true"/>
		<headers>
			<frame-options policy="SAMEORIGIN"/>
		</headers>
	</http>

	<!-- 認證管理器 -->
	<authentication-manager>
		<authentication-provider>
			<user-service>
				<user name="admin" password="123456" authorities="ROLE_ADMIN"/>
				<user name="user" password="123456" authorities="ROLE_ADMIN"/>
			</user-service>
		</authentication-provider>
	</authentication-manager>


</beans:beans>

 

 

 

(3)指定登錄頁面,訪問的action路徑爲Spring Security提供的/login,並配置賬號密碼提交的字段爲username和password

 注意:提交路徑,和name屬性的值都是可以在配置文件中修改的,都可以在form-login 的屬性中配置

<!--  
	login-processing-url="/sysLogin" : 配置登錄請求的路徑
	username-parameter="user" : 配置賬號提交到的字段
	password-parameter="pwd" : 配置密碼提交到的字段
-->

 

(4)指定表單id,並給登錄按鈕設置綁定事件,提交表單

 注意:

    (1)表單提交必須爲post

    (2)提交路徑、賬號和密碼字段,均可以自定義

    (3)登錄成功默認是跳轉到本次會話的上一次沒有訪問成功的頁面,如果沒有就跳轉到默認登錄成功頁面,always-user-default-target="true"配置,可以設置,登陸成功總是跳轉到默認登錄成功頁面,一般後臺管理系統會配置。前臺頁面不配置,用戶體驗會更好。
 

 

 

1.3 登錄後顯示登錄用戶名

(1)後端代碼,新建一個LoginController,用於獲取登錄名並返回到前端

package com.pinyougou.manager.controller;

import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

/**
 * 登錄相關控制層
 * Author xushuai
 * Description
 */
@RestController
@RequestMapping("/login")
public class LoginController {


    /**
     * 返回當前登錄用戶名
     *
     * @return java.util.Map
     */
    @RequestMapping("/showName")
    public Map showName() {
        // 使用spring security的方法獲取
        String name = SecurityContextHolder.getContext().getAuthentication().getName();
        // 封裝到 Map 中
        Map<String, String> map = new HashMap<>();
        map.put("loginName", name);

        return map;
    }
}

 

(2)前端

    a、編寫loginService.js

app.service('loginService', function ($http) {

    //獲取登錄用戶名
    this.showName = function () {
        return $http.get('../login/showName.do');
    }
});

 

    b、編寫indexService.js

 

app.controller('indexController', function ($scope, loginService) {

    // 顯示當前登錄用戶名
    $scope.showName = function () {
        loginService.showName().success(
            function (rtn) {
                $scope.loginName = rtn.loginName;
            }
        );
    }
});

 

    c、頁面引入js文件

 

 

    d、修改所有 "測試用戶" 爲 "{{loginName}}" ,使用查找替換

 

效果:

 

 

1.4 退出登錄

只需要在 spring-security中的http節點中,配置 logout ,然後在前端頁面中的註銷按鈕,請求該 /logout 即可

(1)配置

 

(2)註銷按鈕

 

 

 

 

2、商家申請入駐

 

2.1 前端

(1)爲所有的輸入框綁定提交變量

 

(2)給申請入駐按鈕綁定單擊事件

 

(3)修改前端新增 JS 代碼

 

2.2 後端

只需要在保存之前,補全數據即可(sellergoods-service)

 

 

 

3、商家審覈

 

 

3.1 待審覈商家列表

(1)引入js,在頁面添加分頁控件,在body中引入 ng-app 和 ng-controller

 

(2)循環顯示列表

 

(3)初始化的時候,設置搜索status=0

 

 

 

3.2 查看商家詳情

(1)爲詳情按鈕添加單擊事件

 

(2)綁定變量到需要回顯數據的地方

 

 

3.3 商家狀態修改

(1)服務層接口(sellergoods-interface),新增方法

	/**
	 * 修改商家狀態
	 * 
	 * @param sellerId 商家id
	 * @param status 狀態
	 */
	void updateStatus(String sellerId, String status);

 

(2)服務層實現(sellergoods-service),實現

	@Override
	public void updateStatus(String sellerId, String status) {
		//查詢商家
		TbSeller seller = sellerMapper.selectByPrimaryKey(sellerId);
		if(seller != null) {
			//修改狀態
			seller.setStatus(status);
			//保存
			sellerMapper.updateByPrimaryKey(seller);
		}
	}

 

(3)控制層(SellerController)

    /**
     * 修改商家狀態
     *
     * @return entity.Result
     */
    public Result updateStatus(String sellerId, String status) {
        try {
            sellerService.updateStatus(sellerId, status);
            return Result.success("修改成功");
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("修改失敗");
        }
    }

 

(4)前端sellerService.js新增方法

	//更改狀態
	this.updateStatus = function (sellerId, status) {
		return $http.get('../seller/updateStatus.do?sellerId=' + sellerId + '&status=' + status);
    }

 

(5)前端sellerController.js新增方法

	//修改商家狀態
	$scope.updateStatus = function (sellerId, status) {
		sellerService.updateStatus(sellerId,status).success(
			function (rtn) {
				alert(rtn.message);
				if(rtn.success) {
                    $scope.reloadList();//刷新列表
				}
            }
		);
    }

 

(6)前端按鈕添加單擊事件

 

 

 

 

4、商家系統登錄和安全控制

 

 

4.1 準備工作

(1)引入Spring Security依賴

(2)修改web.xml

(3)修改登錄表單。提交路徑爲"/login";賬號和密碼提交的字段分別爲 username 和password;給按鈕添加單擊事件,用於提交登錄表單數據

 

 

 

4.2 商家登錄

(1)編寫自定義認證類,需要實現 UserDetailsService

package com.pinyougou.shop.security;

import com.pinyougou.pojo.TbSeller;
import com.pinyougou.sellergoods.service.SellerService;
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 java.util.ArrayList;
import java.util.List;

/**
 * Spring Security 自定義認證類
 * Author xushuai
 * Description
 */
public class UserDetailsServiceImpl implements UserDetailsService {


    private SellerService sellerService;

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

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 構建角色列表
        List<GrantedAuthority> authorities = new ArrayList<>();
        // 這個角色名必須在 Spring Security 配置文件中配置
        authorities.add(new SimpleGrantedAuthority("ROLE_SELLER"));

        //按用戶名獲取商家
        TbSeller seller = sellerService.findOne(username);
        if (seller != null) {
            // 判斷商家狀態是否合法
            if(seller.getStatus().equals(TbSeller.STATUS_CHECK)) {// 合法
                /*
                 * 進行校驗:
                 *      Spring Security會自動校驗輸入的username、password,與User對象中的useranme和password進行校驗
                 *      如果校驗成功,就將角色列表中的角色賦予給當前登錄的用戶
                 */
                return new User(username, seller.getPassword(), authorities);
            }
        }

        return null;
    }
}

 

(2) 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:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
	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
						http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

	<!-- 以下頁面不被攔截 -->
	<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>

	<!-- 頁面攔截規則 -->
	<http use-expressions="false">
		<intercept-url pattern="/**" access="ROLE_SELLER" />
		<!--
			login-processing-url="/sysLogin" : 配置登錄請求的路徑
			 username-parameter="user" : 配置賬號提交到的字段
			 password-parameter="pwd" : 配置密碼提交到的字段

			 always-use-default-target :
			 	總是跳轉到默認的登錄成功後顯示的頁面,如果不寫這個配置,
			 	默認登錄成功後首先跳轉到當前會話上次沒有訪問成功的頁面

		 -->
		<form-login login-page="/shoplogin.html"  default-target-url="/admin/index.html"
					authentication-failure-url="/shoplogin.html" always-use-default-target="true"/>
		<!-- 退出登錄 -->
		<logout />
		<csrf disabled="true"/>
		<!-- 配置ifream允許訪問 -->
		<headers>
			<frame-options policy="SAMEORIGIN"/>
		</headers>
	</http>

	<!-- 認證管理器 -->
	<authentication-manager>
		<!-- 指定自定認證類爲認證提供者 -->
		<authentication-provider user-service-ref="userDetailsService"/>
	</authentication-manager>

	<!-- 配置自定義認證類 -->
	<beans:bean id="userDetailsService" class="com.pinyougou.shop.security.UserDetailsServiceImpl">
		<beans:property name="sellerService" ref="sellerService"/>
	</beans:bean>

	<!-- 引用dubbo 服務 -->
	<dubbo:application name="pinyougou-shop-web" />
	<dubbo:registry address="zookeeper://192.168.25.170:2181"/>
	<dubbo:reference id="sellerService" interface="com.pinyougou.sellergoods.service.SellerService"/>
</beans:beans>

 

 

 

4.3 BCrypt加密算法

        用戶表的密碼通常使用MD5等不可逆算法加密後存儲,爲防止彩虹表破解更會先使用一個特定的字符串(如域名)加密,然後再使用一個隨機的salt(鹽值)加密。 特定字符串是程序代碼中固定的,salt是每個密碼單獨隨機,一般給用戶表加一個字段單獨存儲,比較麻煩。 BCrypt算法將salt隨機並混入最終加密後的密碼,驗證時也無需單獨提供之前的salt,從而無需單獨處理salt問題。

 

 

 

4.4 商家入駐時,進行密碼加密

(1)修改SellerController的add方法(shop-web)

 

(2)在spring-security.xml配置文件中,配置登錄時的密碼加密方式

 

 

4.5 商家管理與商家審覈一致,參考商家審覈

 

 

 

5、商家修改資料

 

 

5.1 回顯數據到修改資料頁面

(1)後端,LoginController(shop-web),新增方法獲取當前登錄用戶的id

    /**
     * 返回當前登錄用戶ID
     */
    @RequestMapping("/sellerId")
    public String sellerId() {
        // 使用spring security的方法獲取
        String name = SecurityContextHolder.getContext().getAuthentication().getName();

        return name;
    }

 

5.2 前端

(1)引入js文件,設置ng-app和ng-controller

 

 

(2)輸入框綁定變量,回顯數據

 

 

(3)loginService.js新增方法

    this.sellerId = function () {
        return $http.get('../login/sellerId.do');
    }

 

(4)sellerService.js新增方法

	// 使用id加載當前商家信息
	$scope.sellerId = "";
	$scope.loadId = function () {
		loginService.sellerId().success(
			function (rtn) {
                sellerId = JSON.parse(rtn);
                $scope.findOne(sellerId);
            }
		);
    }

注意:需要注入loginService服務,且前端頁面要引入loginService.js文件

 

(5)頁面初始化運行 loadId()

 

(6)效果

 

 

 

5.2 點擊保存,修改資料(後端部分已由代碼生成器生成)

(1)前端,sellerController.js新增方法

    //更新
    $scope.update=function(){
        sellerService.update( $scope.entity  ).success(
            function(response){
                if(response.success){
                    alert(response.message);
                    $scope.loadId();
                }else{
                    alert(response.message);
                }
            }
        );
    }

 

(2)爲頁面中的 保存按鈕綁定單擊事件

 

 

 

 

6、商家修改密碼

 

 

6.1 後端

(0)新增一個實體類,用於接受前端傳過來的新舊密碼

package entity;

/**
 * 修改密碼時,存放舊密碼和新密碼的實體
 * Author xushuai
 * Description
 */
public class Password {

    private String oldPwd;
    private String newPwd;

    public String getOldPwd() {
        return oldPwd;
    }

    public void setOldPwd(String oldPwd) {
        this.oldPwd = oldPwd;
    }

    public String getNewPwd() {
        return newPwd;
    }

    public void setNewPwd(String newPwd) {
        this.newPwd = newPwd;
    }
}

 

 

 

 

 

(1)服務層接口(sellergoods-interface),新增方法

    /**
     * 修改密碼
     *
     * @param sellerId 商家id
     * @param oldPwd   舊密碼
     * @param newPwd   新密碼
     */
    void updatePassword(String sellerId, String newPwd);

 

(2)服務層實現(sellergoods-service),實現

	@Override
	public void updatePassword(String sellerId, String newPwd) {
		// 查詢商家
		TbSeller seller = sellerMapper.selectByPrimaryKey(sellerId);
		if(seller != null) {
			// 修改密碼
			seller.setPassword(newPwd);
			sellerMapper.updateByPrimaryKey(seller);
		}

	}

 

(3)控制層,shop-web下的SellerController(重點是使用 BCrypt.checkpw() 進行密碼校驗)

    @RequestMapping("/updatePassword")
    public Result updatePassword(@RequestBody Password password) {
        try {
            // 對密碼進行加密處理
            BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
            String newPwd = passwordEncoder.encode(password.getNewPwd());
            //獲取當前登錄的用戶id
            String name = SecurityContextHolder.getContext().getAuthentication().getName();
            TbSeller seller = findOne(name);
            //校驗兩個密碼是否一致
            if(BCrypt.checkpw(password.getOldPwd(),seller.getPassword())) {//一致
                sellerService.updatePassword(name, newPwd);
                return Result.success("修改密碼成功");
            }

            return Result.error("原密碼錯誤");
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("修改密碼失敗");
        }
    }

 

 

 

 

6.2 前端

(1)引入js相關

 

(2)綁定變量到輸入框

 

(3) sellerController.js新增方法

    // 修改密碼
	$scope.updatePassword = function () {
        //校驗兩次密碼是否一致
		if($scope.newPwd != $scope.newPwd1) {
			alert("兩次密碼輸入不一致!");
		} else {
			$scope.password={oldPwd:$scope.oldPwd,newPwd:$scope.newPwd};
			sellerService.updatePassword($scope.password).success(
				function (rtn) {
					alert(rtn.message);
                }
			);
		}
    }

 

(4)sellerService.js新增方法

	//修改密碼
	this.updatePassword = function (password) {
		return $http.post('../seller/updatePassword.do', password);
    }

 

(5)保存按鈕綁定單擊事件

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章