04. SpringSecurity框架-----用户登录拦截的使用

1.SpringSecurity框架介绍

Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。

它可以完成什么工作?

  1. 用户登录,未登录拦截,已登录放行,指定什么页面不拦截




2.具体使用

  1. 导包(在web层添加)
<!-- 身份验证 -->
		<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>




  1. 修改web.xml文件(在web层添加)
	<!-- 读取springSecurity的配置文件 -->
  	 <context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:spring-security.xml</param-value>
	 </context-param>
	 <listener>
		<listener-class>
			org.springframework.web.context.ContextLoaderListener
		</listener-class>
	 </listener>
	 
	<!-- 这是一个过滤器代理类,也是springSecurity的入口,以前我们定义的时候名字都是自定义的随便改,但现在不能改,固定这个名字,不然springSecurity找不到 -->
	 <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>/*  
	 




  1. 书写spring-security.xml配置文件(在web层添加)
    注意页面的标签是 ,与其他页面不同,这个文件也是这个框架的主要配置文件
<?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表达式 默认是true -->
	<http use-expressions="false">
		<!-- 当前用户必须有ROLE_USER的角色 才可以访问根目录及所属子目录的资源 -->
		<intercept-url pattern="/**" access="ROLE_ADMIN"/>
		<!-- 开启表单登陆功能 -->
		<!-- login-page:登录页面;   default-target-url:登录成功跳转页面;     authentication-failure-url:登录失败跳转页面   -->
		<!-- always-use-default-target: 每次登陆都跳转到默认的页面(这里的默认页面:default-target-url="/admin/index.html"),不然会跳转到我们访问时被拦截的页面,这种适用于前端,后端不适合-->
		<form-login  login-page="/login.html" default-target-url="/admin/index.html" authentication-failure-url="/login.html" always-use-default-target="true"/>
		<!-- 如果是jsp页面,就不需要加这个,但是我们这里是html页面,所以我们要关闭它 (不写会报错403-->
		<!-- CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One Click Attack”或者Session Riding,
			通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。 -->
		<csrf disabled="true"/>
		<!-- 默认会拦截<iframe>标签(分区域标签),添加这个即可使其不拦截 -->
		<headers>
			<frame-options policy="SAMEORIGIN"/>
		</headers>
		<!-- 用户退出配置,退户后会自动回到登录页面,自动会生成" /logout ",再到前端注销按钮处配置:href="../logout"../是因为当前是在admin目录下,要返回webapp目录),点一下即可注销用户 -->
		<logout/>
	</http>
	
	<!-- 认证管理器 -->
	<authentication-manager>
		<!-- 还有一种方法设置用户,直接在这个标签中书写用户的账号密码(这里就不演示了) -->
		<!-- 把注入好的用户放入认证管理器中 -->
		<authentication-provider user-service-ref="userDetailService">	
			<!-- 这个是用来解密BCrypt加密算法的, ref 的值在最下面 -->
			<password-encoder ref="bcryptEncoder"></password-encoder>
		</authentication-provider>	
	</authentication-manager>
		
	<!-- 认证类(set注入) -->
	<beans:bean id="userDetailService" class="com.pinyougou.service.UserDetailsServiceImpl">
		<!-- 前面的 sellerService 是UserDetailsServiceImpl.java类中的参数名,后面ref中的这个是下面dubbo中的id属性值   -->
		<beans:property name="sellerService" ref="sellerService"></beans:property>
	</beans:bean>

	<!-- 引用dubbo 服务,引用这dubbo服务是为了通过这个来获取相关的接口,因为SellerService接口不在本地 -->
	<dubbo:application name="pinyougou-shop-web" />
	<dubbo:registry address="zookeeper://192.168.196.134:2181"/>	
	<dubbo:reference id="sellerService" interface="com.pinyougou.sellergoods.service.SellerService"></dubbo:reference>
	
	<!-- 引入加密算法类 -->
	<beans:bean id="bcryptEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"></beans:bean>
		
</beans:beans>




  1. 认证类 UserDetailsServiceImpl.java , 这个类配合spring-security.xml配置文件看

public class UserDetailsServiceImpl implements UserDetailsService {

	//因为这是单独的,只有这个类,所以这里我们使用set()方法注入
	private SellerService sellerService;
	
	public void setSellerService(SellerService sellerService) {
		this.sellerService = sellerService;
	}

	//用户点击登录会自动运行这个方法(这个类继承了SpringSecurity框架中的接口)
	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {


		//获取登录者的用户名(这里用不到,但是还是得记住这句话)
		String name = SecurityContextHolder.getContext().getAuthentication().getName();


		System.out.println("经过了UserDetailsServiceImpl");//用于观察方法是否经过这个类
		
		//构建角色列表
		List<GrantedAuthority> grantAuths=new ArrayList();//这里面放置的是角色列表
		grantAuths.add(new SimpleGrantedAuthority("ROLE_SELLER"));//这里是给角色列表构建一个角色
		
		//得到商家对象
		TbSeller seller = sellerService.findOne(username);//通过输入的用户名找到相关的商家信息
		if(seller!=null){
			if(seller.getStatus().equals("1")){//判断,如果为1就让他通过(状态值:  0:未审核   1:已审核   2:审核未通过   3:关闭)
				return new User(username,seller.getPassword(),grantAuths);
			}else{
				return null;
			}			
		}else{
			return null;
		}
	}

}





  1. html页面的一些配置

        a.提交页面的 “action” 地址

<!-- action中的提交地址是 SpringSecurity 框架自动给你生成的-->
<form class="sui-form" action="/login" method="post" id="loginform">

        c. 登录按钮

<div class="logined">
	<!-- 如果不想用按钮则可以用这种方式提交表单,loginform对应<form>标签中的id值 -->
	<a class="sui-btn btn-block btn-xlarge btn-danger" onclick="document:loginform.submit()" target="_blank">&nbsp;&nbsp;</a>
</div>

        b.注销用户的注销按钮

<div class="pull-right">
	<!--"spring-security.xml" 中的 <logout/> 相对应 -->
	<a href="../logout" class="btn btn-default btn-flat">注销</a>
</div>




2. 密码加密

  1. BCrypt加密算法

用户表的密码通常使用MD5等不可逆算法加密后存储,为防止彩虹表破解更会先使用一个特定的字符串(如域名)加密,然后再使用一个随机的salt(盐值)加密。 特定字符串是程序代码中固定的,salt是每个密码单独随机,一般给用户表加一个字段单独存储,比较麻烦。 BCrypt算法将salt随机并混入最终加密后的密码,验证时也无需单独提供之前的salt,从而无需单独处理salt问题。

  1. 具体使用

a. 在增加方法中添加加密方法(SellerController.java类中)

	/**
	 * 增加
	 * @param seller
	 * @return
	 */
	@RequestMapping("/add")
	public Result add(@RequestBody TbSeller seller){
		//密码加密
		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, "增加失败");
		}
	}



b.在登录方法中增加解密方法( spring-security.xml配置文件中)

	<!-- 认证管理器 -->
	<authentication-manager>
		<!-- 把注入好的用户放入认证管理器中 -->
		<authentication-provider user-service-ref="userDetailService">	
			<!-- 这个是用来解密BCrypt加密算法的, ref 的值在最下面 -->
			<password-encoder ref="bcryptEncoder"></password-encoder>
		</authentication-provider>	
	</authentication-manager>
	
			<!-- 引入加密算法类 -->
	<beans:bean id="bcryptEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"></beans:bean>

你可能感兴趣的:(SpringSecurity)