品优购项目记录: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)保存按钮绑定单击事件

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值