学习目标
目标1:实现SpringSecurity入门小Demo
目标2:完成运营商登陆与安全控制功能
目标3:完成商家入驻
目标4:完成商家审核
目标5:完成商家系统登陆与安全控制功能
一、SpringSecurity入门Demo
1.创建springSecurityDemo的war工程 2.pom文件及web.xml的导入从资源->配置文件->SpringSecurity中拷贝 3.创建index.html欢迎页 4.修改spring-security.xml文件
<!-- 设置页面不登陆也可以访问 -->
<http pattern="/login.html" security="none"></http>
<http pattern="/login_error.html" security="none"></http>
<!-- 页面的拦截规则 use-expressions:是否启动SPEL表达式 默认是true -->
<http use-expressions="false">
<!-- 当前用户必须有ROLE_USER的角色 才可以访问根目录及所属子目录的资源 -->
<intercept-url pattern="/**" access="ROLE_USER"/>
<!-- 开启表单登陆功能,自定义登录页login.html,错误跳转页login_error.html -->
<form-login login-page="/login.html" default-target-url="/index.html" authentication-failure-url="/login_error.html"/>
<!--解决跨域访问错误问题-->
<csrf disabled="true"/>
<!-- <form-login /> -->
</http>
<!-- 认证管理器 -->
<authentication-manager>
<authentication-provider>
<user-service>
<user name="admin" password="123456" authorities="ROLE_USER"/>
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
5.如果不想第一次登录的时候看到错误提示,将favicon.ico文件拷贝webapp目录 6.login.html内容是
--欢迎的登陆我的系统--
<form action="/login" method="post">
用户名:<input name="username"><br>
密码:<input name="password"><br>
<button>登陆</button>
</form>
二、运营商系统
1.pinyougou-manager-web的pom文件加入两个依赖(该依赖已经添加到父工程中,可以跳过)
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
</dependency>
2.web.xml文件将spring-security的配置放到springmvc下面,注意配置文件路径 3.pinyougou-manager-web加入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="/*.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>
<!-- 页面的拦截规格 use-expressions:默认启用SPEL表达式 需要将 access="hasRole('ROLE_USER')" -->
<http use-expressions="false">
<!-- 当前用户必须有ROLE_USER的角色才可以访问根目录及所属子目录的资源 ROLE_是固定写法-->
<intercept-url pattern="/**" access="ROLE_USER" />
<!-- 开启表单登录功能 csrf跨域访问需要jsp页,因为是html的所以需要关闭-->
<form-login login-page="/login.html" default-target-url="/admin/index.html" authentication-failure-url="/login.html"/>
<csrf disabled="true"/>
</http>
<!-- 认证管理器 -->
<authentication-manager>
<!-- 认证提供者 -->
<authentication-provider>
<user-service>
<!-- 配置当前系统的用户 authorities该用户属于哪个角色 -->
<user name="admin" password="123456" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
2.login.html页面的用户名密码的form表单处的action="/login",这里的login是默认的,可以通过修改login-processing-url属性来替换掉默认的login 3.配置文件可以对username和password进行重命名
<!--提交表单的地址就改成login2,password-parameter提交的密码改名-->
<form-login password-parameter="pass" username-parameter="user" login-processing-url="/login2" login-page="/login.html" default-target-url="/admin/index.html" authentication-failure-url="/login.html"/>
当前页面的输入表单绑定用户名和密码,username和password也可以修改,参照上面的配置
注意页面的action地址,如果是tomcat启动需要加上项目路径
<form class="sui-form" action="/login" method="post" id="loginform">
...
<input id="prependedInput" name="user" type="text" placeholder="邮箱/用户名/手机号" class="span2 input-xfat">
...
<input id="prependedInput" name="pass" type="password" placeholder="请输入密码" class="span2 input-xfat">
...
<a class="sui-btn btn-block btn-xlarge btn-danger" target="_blank" onclick="document:loginform.submit()">登 录</a>
界面看不到详细页,报错
页面报错:Refused to display 'http://localhost:9101/pinyougou-manager-web/admin/home.html' in a frame because it set 'X-Frame-Options' to 'deny'.
<!-- 页面的拦截规则 use-expressions:是否启动SPEL表达式 默认是true -->
<http use-expressions="false">
...上面重复
<headers>
//DENY:浏览器拒绝当前页面加载任何Frame页面
//SAMEORIGIN:frame页面的地址只能为同源域名下的页面
//ALLOW-FROM:origin为允许frame加载的页面地址。
<frame-options policy="SAMEORIGIN"/>
</headers>
</http>
三、显示登录名
1.增加LoginController.java
package com.pinyougou.manager.controller;
import java.util.HashMap;
import java.util.Map;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/login")
public class LoginController {
@RequestMapping("/name")
public Map name(){
String name = SecurityContextHolder.getContext().getAuthentication().getName();
Map map = new HashMap<>();
map.put("loginName", name);
return map;
}
}
2.增加loginService.js
app.service('loginService',function($http){
this.loginName = function(){
return $http.get('../login/name.do');
}
});
3.增加loginController.js
app.controller('loginController',function($scope,loginService){
//显示当前用户名
$scope.showLoginName=function(){
loginService.loginName().success(
function(response){
$scope.loginName=response.loginName;
}
);
}
})
4.index.html修改
//导入js引用
...
<script type="text/javascript" src="../plugins/angularjs/angular.min.js"></script>
<script type="text/javascript" src="../js/base.js" ></script>
<script type="text/javascript" src="../js/service/loginService.js" ></script>
<script type="text/javascript" src="../js/controller/loginController.js" ></script>
</head>
//修改body中的初始化
<body class="hold-transition skin-green sidebar-mini" ng-app="pinyougou" ng-controller="loginController" ng-init="showLoginName()">
...
//测试用户文本替换成{{loginName}}显示当前用户名,一共三处进行用户名的替换
四、退出登录
1.在spring-security.xml文件中增加
<http use-expressions="false">
....省略//这里增加logout后,可通过logout进行调用
<logout/>
</http>
2.在index.html中将注销按钮修改**href="../logout"**
五、商家申请入驻
1.创建pinyougou-shop-web商家web模块 1.拷贝商家管理后台静态资源到pinyougou-shop-web 2.拷贝文件**前方高能,注意修改主键类型,seller主键是String类型!!!**
======sellergoods-interface子模块中拷贝 (1)GoodsService.java (2)SellerService.java ======sellergoods-service子模块中拷贝 (1)GoodsServiceImpl.java (2)SellerServiceImpl.java ======shop-web项目创建js文件夹,文件夹下创建service和controller文件夹,从代码生成器中拷贝下面6个 (1)goodsService.js (2)sellerService.js (3)goodsController.js (4)sellerController.js (5)GoodsController.java (6)SellerController.java =======shop-web项目拷贝,从pinyougou-manager-web项目拷贝下面三个文件: (1)baseController.js (2)base_pagination.js (3)base.js
3.pinyougou-shop-web项目的pom文件引入pinyougou-sellergoods-interface 4.在register.html中进行修改
//需要引入相关js文件
<script type="text/javascript" src="plugins/angularjs/angular.min.js"></script>
<script type="text/javascript" src="js/base.js" ></script>
<script type="text/javascript" src="js/service/sellerService.js" ></script>
<script type="text/javascript" src="js/controller/baseController.js" ></script>
<script type="text/javascript" src="js/controller/sellerController.js" ></script>
...
//需要在body中
<body ng-app="pinyougou" ng-controller="sellerController">
//每个intput标签绑定属性
<input type="text" placeholder="登陆名" ng-model="entity.sellerId" 其他省略...">
//最后保存按钮去掉href替换成ng-click
<a class="...省略" ng-click="save()" target="_blank">申请入驻</a>
5.需要在sellerController.js文件中增加add方法
//新增
$scope.add=function(){
sellerService.add( $scope.entity ).success(
function(response){
if(response.success){
//如果注册成功跳转到登录页面
location.href="shoplogin.html";
}else{
alert(response.message);
}
}
);
}
6.关于新增后初始值默认值处理SellerServiceImpl.java的add方法修改
public void add(TbSeller seller) {
seller.setStatus("0"); //状态初始化 0:未审核 1:已审核 2:已驳回 3:已停用
seller.setCreateTime(new Date());//日期初始化
sellerMapper.insert(seller);
}
六、商家待审核列表
1.pinyougou-manager-web工程中的seller_1.html
//1.拷贝以下三个文件到manager-web项目 sellerService.js,sellerController.js,sellerController.java //2.body中做配置
<body class="hold-transition skin-red sidebar-mini" ng-app="pinyougou" ng-controller="sellerController" ng-init="searchEntity={status:'0'}">
//3.修改tr内容为循环
<tr ng-repeat="entity in list">
<td><input type="checkbox"></td>
<td>{{entity.sellerId}}</td>
<td>{{entity.name}}</td>
<td>{{entity.nickName}}</td>
<td>{{entity.linkmanName}}</td>
<td>{{entity.telephone}}</td>
<td class="text-center">
<button type="button" class="btn bg-olive btn-xs" data-toggle="modal" data-target="#sellerModal" >详情</button>
</td>
</tr>
//4.分页控件
<tm-pagination conf="paginationConf" />
七、商家详情
1.seller_1.html详情按钮增加ng-click="findOne(entity.sellerId)"
<tr>
<td>公司名称</td>
<td>{{entity.name}}</td>
</tr>
<tr>
<td>店铺名称</td>
<td>{{entity.nickName}}</td>
</tr>
<tr>
<td>公司电话</td>
<td>{{entity.telephone}}</td>
</tr>
<tr>
<td>公司详细地址</td>
<td>{{entity.addressDetail}}</td>
</tr>
八、商家审核
1.SellerService接口类增加方法
public void updateStatus(String sellerId,String status);
2.SellerServiceImpl.java实现updateStatus方法
public void updateStatus(String sellerId, String status) {
// TODO Auto-generated method stub
TbSeller seller = sellerMapper.selectByPrimaryKey(sellerId);
seller.setStatus(status);
sellerMapper.updateByPrimaryKey(seller);
}
3.SellerController.java增加updateStatus方法
@RequestMapping("/updateStatus")
public Result updateStatus(String sellerId, String status) {
try {
sellerService.updateStatus(sellerId, status);
return new Result(true, "成功");
} catch (Exception e) {
e.printStackTrace();
return new Result(false,"失败");
}
}
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(response){
if(response.success){
$scope.reloadList();
}else{
alert(response.message);
}
}
);
}
6.seller_1.html中的审核按钮增加点击效果
<button class="btn btn-success" data-dismiss="modal" aria-hidden="true" ng-click="updateStatus(entity.sellerId,'1')">审核通过</button>
<button class="btn btn-danger" data-dismiss="modal" aria-hidden="true" ng-click="updateStatus(entity.sellerId,'2')">审核未通过</button>
<button class="btn btn-danger" data-dismiss="modal" aria-hidden="true" ng-click="updateStatus(entity.sellerId,'3')">关闭商家</button>
九、商家登录系统与安全控制
//整体流程 1.authentication-provider中设置user-service-ref 2.需要创建个userDetialService的beans,注入sellerService 3.sellerService得从dubbo中获取 4.编写UserDetailsServiceImpl实现UserDetailsService 返回的new User(用户名,密码,角色集合);
1.拷贝web.xml文件中的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">
<!-- 设置页面不登陆也可以访问 -->
<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 pattern="/shoplogin.html" security="none"></http>
<!-- 页面的拦截规则 use-expressions:是否启动SPEL表达式 默认是true -->
<http use-expressions="false">
<!-- 当前用户必须有ROLE_USER的角色 才可以访问根目录及所属子目录的资源 -->
<intercept-url pattern="/**" access="ROLE_USER"/>
<!-- 开启表单登陆功能 -->
<form-login login-page="/shoplogin.html" default-target-url="/admin/index.html" authentication-failure-url="/shoplogin.html" always-use-default-target="true"/>
<csrf disabled="true"/>
<headers>
<frame-options policy="SAMEORIGIN"/>
</headers>
<logout/>
</http>
<!-- 认证管理器 -->
<authentication-manager>
<authentication-provider user-service-ref="userDetialService">
</authentication-provider>
</authentication-manager>
<!-- 认证类 -->
<beans:bean id="userDetialService" class="com.pinyougou.service.UserDetailsServiceImpl">
<beans:property name="sellerService" ref="sellerService"></beans:property>
</beans:bean>
<!-- 引用dubbo 服务 -->
<dubbo:application name="pinyougou-shop-web" />
<dubbo:registry address="zookeeper://192.168.25.130:2181"/>
<dubbo:reference id="sellerService" interface="com.pinyougou.sellergoods.service.SellerService" />
</beans:beans>
2.shoplogin.html页面修改表单提交部分
<form class="sui-form" method="post" action="/login" method="post" id="loginform">
<input id="prependedInput" type="text" name="username" placeholder="邮箱/用户名/手机号" class="span2 input-xfat">
<input id="prependedInput" type="password" name="password" placeholder="请输入密码" class="span2 input-xfat">
//登录按钮增加点击提交表单
<a class="sui-btn btn-block btn-xlarge btn-danger" onclick="document:loginform.submit()" target="_blank">登 录</a>
3.在shop系统中增加com.pinyougou.service包
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;
public class UserDetailsServiceImpl implements UserDetailsService{
private SellerService sellerService;
public void setSellerService(SellerService sellerService) {
this.sellerService = sellerService;
}
@Override
public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException {
System.out.println("经过了UserDetailsServiceImpl");
//构建角色列表
List<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
TbSeller seller = sellerService.findOne(name);
if(seller!=null&&seller.getStatus().equals("1")){
//测试的时候注意用户需要状态为1已审核的
return new User(name, seller.getPassword(), authorities);
}else{
return null;
}
}
}
十、BCrypt加密
1.SellerController.java的add方法增加加密密码功能
public Result add(@RequestBody TbSeller seller){
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
String encode = encoder.encode(seller.getPassword());
seller.setPassword(encode);
try {
sellerService.add(seller);
return new Result(true, "增加成功");
} catch (Exception e) {
e.printStackTrace();
return new Result(false, "增加失败");
}
}
2.在spring-security.xml配置下面增加密码加密
<authentication-provider user-service-ref="userDetialService">
<!-- 增加这行是为了支持密码加密 -->
<password-encoder ref="passwordEncoder"></password-encoder>
</authentication-provider>
<beans:bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"></beans:bean>
3.测试的时候记得商户状态需要手动改为1,才可以登录成功