更多内容,前往IT-BLOG

一、Spring Security 简介


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

二、Spring Security 入门Demo


【1】创建 Maven工程(war形式):spring-security-demo
【2】修改 pom.xml目录,如下:

  1 <!-- 集中定义依赖版本号 -->
2 <properties>
3 <junit.version>4.12</junit.version>
4 <spring.version>4.2.4.RELEASE</spring.version>
5 <pagehelper.version>4.0.0</pagehelper.version>
6 <servlet-api.version>2.5</servlet-api.version>
7 <dubbo.version>2.8.4</dubbo.version>
8 <zookeeper.version>3.4.7</zookeeper.version>
9 <zkclient.version>0.1</zkclient.version>
10 <mybatis.version>3.2.8</mybatis.version>
11 <mybatis.spring.version>1.2.2</mybatis.spring.version>
12 <mybatis.paginator.version>1.2.15</mybatis.paginator.version>
13 <mysql.version>5.1.32</mysql.version>
14 <druid.version>1.0.9</druid.version>
15 <commons-fileupload.version>1.3.1</commons-fileupload.version>
16 <freemarker.version>2.3.23</freemarker.version>
17 <activemq.version>5.11.2</activemq.version>
18 <security.version>3.2.3.RELEASE</security.version>
19 <solrj.version>4.10.3</solrj.version>
20 <ik.version>2012_u6</ik.version>
21 </properties>
22 <dependencies>
23 <dependency>
24 <groupId>org.springframework</groupId>
25 <artifactId>spring-core</artifactId>
26 <version>${spring.version}</version>
27 </dependency>
28 <dependency>
29 <groupId>org.springframework</groupId>
30 <artifactId>spring-web</artifactId>
31 <version>${spring.version}</version>
32 </dependency>
33
34 <dependency>
35 <groupId>org.springframework</groupId>
36 <artifactId>spring-webmvc</artifactId>
37 <version>${spring.version}</version>
38 </dependency>
39
40 <dependency>
41 <groupId>org.springframework</groupId>
42 <artifactId>spring-context-support</artifactId>
43 <version>${spring.version}</version>
44 </dependency>
45
46 <dependency>
47 <groupId>org.springframework</groupId>
48 <artifactId>spring-test</artifactId>
49 <version>${spring.version}</version>
50 </dependency>
51
52 <dependency>
53 <groupId>org.springframework</groupId>
54 <artifactId>spring-jdbc</artifactId>
55 <version>${spring.version}</version>
56 </dependency>
57
58 <dependency>
59 <groupId>org.springframework.security</groupId>
60 <artifactId>spring-security-web</artifactId>
61 <version>4.1.0.RELEASE</version>
62 </dependency>
63
64 <dependency>
65 <groupId>org.springframework.security</groupId>
66 <artifactId>spring-security-config</artifactId>
67 <version>4.1.0.RELEASE</version>
68 </dependency>
69
70 <dependency>
71 <groupId>javax.servlet</groupId>
72 <artifactId>servlet-api</artifactId>
73 <version>2.5</version>
74 <scope>provided</scope>
75 </dependency>
76
77 </dependencies>
78 <build>
79 <plugins>
80 <!-- java编译插件 -->
81 <plugin>
82 <groupId>org.apache.maven.plugins</groupId>
83 <artifactId>maven-compiler-plugin</artifactId>
84 <version>3.2</version>
85 <configuration>
86 <source>1.7</source>
87 <target>1.7</target>
88 <encoding>UTF-8</encoding>
89 </configuration>
90 </plugin>
91 <plugin>
92 <groupId>org.apache.tomcat.maven</groupId>
93 <artifactId>tomcat7-maven-plugin</artifactId>
94 <configuration>
95 <!-- 指定端口 -->
96 <port>9090</port>
97 <!-- 请求路径 -->
98 <path>/</path>
99 </configuration>
100 </plugin>
101 </plugins>
102 </build>

注意:如果只是给自己的项目中嵌入 Spring Security 安全框架,只需要添加如下两个 jar 包即可。

 1 <dependency>
2 <groupId>org.springframework.security</groupId>
3 <artifactId>spring-security-web</artifactId>
4 <version>4.1.0.RELEASE</version>
5 </dependency>
6
7 <dependency>
8 <groupId>org.springframework.security</groupId>
9 <artifactId>spring-security-config</artifactId>
10 <version>4.1.0.RELEASE</version>
11 </dependency>

【3】创建 web.xml 文件(通过 Spring Security 拦截需要处理的请求和引入 Spring Security 的配置文件)。

 1 <?xml version="1.0" encoding="UTF-8"?>
2 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3 xmlns="http://java.sun.com/xml/ns/javaee"
4 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
5 version="2.5">
6 <!-- 引入spring-security框架的配置文件 -->
7 <context-param>
8 <param-name>contextConfigLocation</param-name>
9 <param-value>classpath:spring-security.xml</param-value>
10 </context-param>
11 <listener>
12 <listener-class>
13 org.springframework.web.context.ContextLoaderListener
14 </listener-class>
15 </listener>
16 <!-- 通过spring-security 内置的拦截器 springSecurityFilterChain 拦截 /* 的请求,名称不能修改,安全框架的入口配置 -->
17 <!-- 所有的请求通过拦截器(DelegatingFilterProxy)拦截后,找名为 springSecurityFilterChain 类进行逻辑处理,此类是spring security安全框架中所包含的类 -->
18 <filter>
19 <filter-name>springSecurityFilterChain</filter-name>
20 <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
21 </filter>
22 <filter-mapping>
23 <filter-name>springSecurityFilterChain</filter-name>
24 <url-pattern>/*</url-pattern>
25 </filter-mapping>
26 </web-app>

【4】创建 Spring Security 配置文件:spring-security.xml(与 web.xml 中引入的配置文件对应),代码中有配置的详细说明注解。

 1 <?xml version="1.0" encoding="UTF-8"?>
2 <!-- 此配置将Spring Seucrity设置成了默认标签,其他使用时,需要添加如下前缀beans或dubbo等 -->
3 <beans:beans
4 xmlns="http://www.springframework.org/schema/security"
5 xmlns:beans="http://www.springframework.org/schema/beans"
6 xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
7 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
8 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
9 http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd
10 http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
11
12 <!-- 登录页面不能拦截 none任何角色都可访问
13 如果你没有设置登录页security="none" ,将会出现以下错误 :"重定向次数过多"因为登录页会被反复重定向-->
14 <http pattern="/*.html" security="none"></http>
15 <http pattern="/css/**" security="none"></http>
16 <http pattern="/img/**" security="none"></http>
17 <http pattern="/js/**" security="none"></http>
18 <http pattern="/plugins/**" security="none"></http>
19 <!-- 注意:如果是用户申请登录名的请求也不能拦截 -->
20 <http pattern="/seller/add.do" security="none"></http>
21 <!-- 拦截页面 -->
22 <!-- use-expressions -为是否使用 Spring 表达式语言( SpEL ),默认为true ,如果开启,则拦截的配置应该写成以下形式
23 <intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
24 -->
25 <http use-expressions="false">
26 <!--
27 /* 表示的是该目录下的资源,只包括本级目录不包括下级目录
28 /** 表示的是该目录以及该目录下所有级别子目录的资源
29 -->
30 <intercept-url pattern="/**" access="ROLE_SELLER" />
31 <!-- form-login:开启表单登录,默认登录请求/login可以通过配置修改默认请求
32 always-use-default-target:指定了是否在身份验证通过后总是跳转到default-target-url属性指定的URL。
33 authentication-failure-url:登录失败,跳转页面 -->
34 <form-login login-page="/login.html"
35 default-target-url="/index.html"
36 authentication-failure-url="/login_error.html"
37 always-use-default-target="true" />
38 <!-- csrf disabled="true" 关闭csrf ,如果不加会出现错403 这种一般会自动生成在请求头信息中:
39 'X-CSRF-TOKEN'(相当于一个校徽)防止跨站点攻击,但只能jsp实现,html不能实现,因此需要关闭此功能
40 CSRF(Cross-site request forgery)跨站请求伪造,
41 也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。-->
42 <csrf disabled="true" />
43 <!-- 当页面中存在嵌入式iframe时,需要配置hears -->
44 <headers>
45 <frame-options policy="SAMEORIGIN" />
46 </headers>
47 <!-- 登出,页面只需要发送/logout请求就可会触发 也可以修改默认的处理,例如logout-url=""可以修改登出的请求-->
48 <logout />
49 </http>
50 <!-- Spring Security中 用户登录时认证管理器 -->
51 <!-- Spring Security是如何完成身份认证的?
52 ①、用户名和密码被过滤器获取到,封装成Authentication,通常情况下是UsernamePasswordAuthenticationToken这个实现类。
53 ②、AuthenticationManager 身份管理器负责验证这个Authentication。
54 ③、认证成功后,AuthenticationManager身份管理器返回一个被填充满了信息的(包括上面提到的权限信息,身份信息,细节信息,但密码通常会被移除)Authentication实例。
55 ④、SecurityContextHolder安全上下文容器将第3步填充了信息的Authentication,
56 通过SecurityContextHolder.getContext().setAuthentication(…)方法,设置到其中。 -->
57 <authentication-manager>
58 <!-- user-service-ref 指向用户认证业务处理类,需要实现UserDetailsService接口-->
59 <!-- 如果测试,不想从数据库中获取用户,可以直接配置一个用户名和密码 ,特换掉如下authentication-provider内的配置即可。 -->
60 <authentication-provider>
61 <user-service>
62 <user name="admin" password="123456" authorities="ROLE_USER"/>
63 </user-service>
64 </authentication-provider>
65
66 <!-- <authentication-provider user-service-ref="userDetailServiceImpl">
67 对密码进行bcrypt加密,比较时需要解密后处理,bcrypt与MD5不同,
68 MD5加密后相同的密码生成相同的16位字符创,bcrybt相同的密码加密后生成不同的30位字符串,
69 相当于MD5+盐
70 <password-encoder hash="bcrypt"></password-encoder>
71 </authentication-provider> -->
72 </authentication-manager>
73 <!-- <beans:bean id="userDetailServiceImpl" class="com.pinyougou.shop.service.UserDetailServiceImpl">
74 当自己的项目需要使用另一个项目中的服务类时 ,需要通过dubbo引入项目 dubbo标签
75 <beans:property name="sellerService" ref="sellerService"></beans:property>
76 </beans:bean> -->
77
78
79 <!-- 引用dubbo sellerService服务:供登录用户业务处理类使用 -->
80 <!-- <dubbo:application name="pinyougou-shop-web" />
81 <dubbo:registry address="zookeeper://192.168.159.129:2181" />
82 <dubbo:reference id="sellerService"
83 interface="com.pinyougou.sellergoods.service.SellerService"></dubbo:reference> -->
84 </beans:beans>

【5】需要自己创建:login.html(登录页面 如下)、index.html(登录成功跳转页面)、login_error.html(登录失败跳转页面)

 1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="UTF-8">
5 <title>登陆</title>
6 </head>
7 <body>
8 --欢迎登陆我的系统--
9 <form action="/login" method="post">
10 用户名:<input name="username"><br>
11 密码:<input name="password"><br>
12 <button>登陆</button>
13 </form>
14 </body>
15 </html>

三、项目实战中,后台业务逻辑实现重要代码摘取,供实战中使用


【1】配置文件中配置的,登录时用户名和密码的业务逻辑处理类(实现 UserDetailsService:框架自带的接口),注意:普通 demo 不需要此部分,主要用于真是环境登录逻辑的处理。

 1 public class UserDetailServiceImpl implements UserDetailsService {
2 //当通过配置文件的形式,引入服务类时需要设置set方法。
3 private SellerService sellerService;
4
5 public void setSellerService(SellerService sellerService) {
6 this.sellerService = sellerService;
7 }
8
9 @Override
10 public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
11 //GrantedAuthority : 定义用户角色,需要实现的接口
12 List<GrantedAuthority> list =new ArrayList<>();
13 //用户添加角色,SimpleGrantedAuthority可以定义用户角色,实现了GrantedAuthority接口,
14 //格式必须以(ROLE_)开头
15 list.add(new SimpleGrantedAuthority("ROLE_SELLER"));
16 //从数据库中获取用户信息。
17 TbSeller seller = sellerService.findOne(username);
18 if(seller != null) {
19 //返回username:传过来的参数。seller.getPassword:数据库中获取到的用户密码。
20 //list:用户的所有角色,可以从数据库中获取
21 return new User(username, seller.getPassword(), list);
22 }else {
23 return null;
24 }
25 }
26 }

【2】BCrypt 加密过程(配置中说明了 BCrypt 与 MD5 的区别)。

 1 @RequestMapping("/add")
2 public Result add(@RequestBody TbSeller seller){
3 try {
4 //BCrypt加密使用的对象BCryptPasswordEncoder
5 BCryptPasswordEncoder cryptPasswordEncoder = new BCryptPasswordEncoder();
6 //使用encode方法对传入的密码加密,返回30位的字符串
7 String encode = cryptPasswordEncoder.encode(seller.getPassword());
8 //业务处理:接入对象中
9 seller.setPassword(encode);
10 //调用服务层,入库
11 sellerService.add(seller);
12 return new Result(true, "增加成功");
13 } catch (Exception e) {
14 e.printStackTrace();
15 return new Result(false, "增加失败");
16 }
17 }

四、当程序中需要用户名时,可通过 SecurityContextHolder 对象获取


SecurityContextHolder 用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保存在 SecurityContextHolder 中。SecurityContextHolder 默认使用 ThreadLocal  策略来存储认证信息。看到 ThreadLocal 也就意味着,这是一种与线程绑定的策略。Spring Security 在用户登录时自动绑定认证信息到当前线程,在用户退出时,自动清除当前线程的认证信息。但这一切的前提,是你在 web 场景下使用 Spring Security。
☏ 因为身份信息是与线程绑定的,所以可以在程序的任何地方使用静态方法获取用户信息。一个典型的获取当前登录用户的姓名的例子如下所示:getAuthentication() 返回了认证信息。

1 @RequestMapping("/name")
2 public Map<String, String> getName(){
3 //获取登录名
4 String name = SecurityContextHolder.getContext().getAuthentication().getName();
5 Map<String, String> map = new HashMap<>();
6 map.put("loginName", name);
7 return map;
8 }

☏ Authentication 源码:

1 package org.springframework.security.core;// <1>
2 public interface Authentication extends Principal, Serializable { // <1>
3 Collection<? extends GrantedAuthority> getAuthorities(); // <2>
4 Object getCredentials();// <2>
5 Object getDetails();// <2>
6 Object getPrincipal();// <2>
7 boolean isAuthenticated();// <2>
8 void setAuthenticated(boolean var1) throws IllegalArgumentException;
9 }

【1】Authentication 是 Spring Security 包中的接口,直接继承自 Principal 类,而 Principal 是位于 java.security 包中的。可以见得,Authentication 在 Spring Security 中是最高级别的身份/认证的抽象。
【2】由这个顶级接口,我们可以得到用户拥有的权限信息列表,密码,用户细节信息,用户身份信息,认证信息。
authentication.getPrincipal() 返回了一个 Object,我们将 Principal 强转成了Spring Security 中最常用的 UserDetails,这在Spring Security 中非常常见,接口返回 Object,使用 instanceof 判断类型,强转成对应的具体实现类。接口详细解读如下:
getAuthorities():权限信息列表,默认是GrantedAuthority接口的一些实现类,通常是代表权限信息的一系列字符串。
getCredentials():密码信息,用户输入的密码字符串,在认证过后通常会被移除,用于保障安全。
getDetails():细节信息,web应用中的实现接口通常为 WebAuthenticationDetails,它记录了访问者的 ip地址和 sessionId的值。
getPrincipal():最重要的身份信息,大部分情况下返回的是UserDetails接口的实现类,也是框架中的常用接口之一。


 ----关注公众号,获取更多内容----

Spring Security 框架使用的更多相关文章

  1. Spring Security框架进阶、自定义登录

      1.Spring Security框架进阶 1.1 Spring Security简介 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安 ...

  2. Spring Security框架入门

    1.Spring Security框架入门 1.1 Spring Security简介 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框 ...

  3. Spring Security框架中踢人下线技术探索

    1.背景 在某次项目的开发中,使用到了Spring Security权限框架进行后端权限开发的权限校验,底层集成Spring Session组件,非常方便的集成Redis进行分布式Session的会话 ...

  4. Spring Security框架下Restful Token的验证方案

    项目使用Restful的规范,权限内容的访问,考虑使用Token验证的权限解决方案. 验证方案(简要概括): 首先,用户需要登陆,成功登陆后返回一个Token串: 然后用户访问有权限的内容时需要上传T ...

  5. 1. Spring Security 框架简介

    官网:https://projects.spring.io/spring-security/Spring Security 是强大的,且容易定制的实现认证,与授权的基于 Spring 开发的框架.Sp ...

  6. Spring Security框架下实现两周内自动登录"记住我"功能

    本文是Spring Security系列中的一篇.在上一篇文章中,我们通过实现UserDetailsService和UserDetails接口,实现了动态的从数据库加载用户.角色.权限相关信息,从而实 ...

  7. 在Spring Security框架下JWT的实现细节原理

    一.回顾JWT的授权及鉴权流程 在笔者的上一篇文章中,已经为大家介绍了JWT以及其结构及使用方法.其授权与鉴权流程浓缩为以下两句话 授权:使用可信用户信息(用户名密码.短信登录)换取带有签名的JWT令 ...

  8. SpringBoot 整合Spring Security框架

    引入maven依赖 <!-- 放入spring security依赖 --> <dependency> <groupId>org.springframework.b ...

  9. Spring Security安全框架

    今天来简单介绍一下Spring Security安全框架 简介 Spring Security 提供了基于javaEE的企业应有个你软件全面的安全服务.这里特别强调支持使用SPring框架构件的项目, ...

  10. 使用 Spring Security 保护 Web 应用的安全

    安全一直是 Web 应用开发中非常重要的一个方面.从安全的角度来说,需要考虑用户认证和授权两个方面.为 Web 应用增加安全方面的能力并非一件简单的事情,需要考虑不同的认证和授权机制.Spring S ...

随机推荐

  1. OC底层知识之 性能优化

    一.CPU和GPU 的介绍 1.1.在屏幕成像的过程中,CPU和GPU起着至关重要的作用 CPU(Central Processing Unit,中央处理器),对象的创建和销毁.对象属性的调整.布局计 ...

  2. iOS用runtime给一个类动态添加方法 ---class_addMethod

    先介绍下class_addMethod这个fangfa   /**   * Adds a new method to a class with a given name and implementat ...

  3. Spark RDD编程

    1. 准备文本文件从文件创建RDD lines=sc.textFile()筛选出含某个单词的行 lines.filter()lambda 参数:条件表达式 2. 生成单词的列表从列表创建RDD wor ...

  4. 在Unity3D中开发的角色视觉系统插件Sight Detect System

    Sight-Detect-System 这款Sight Detect System插件由本人用Unity3D所开发,它在游戏中可以成为角色的视觉感知系统. 如果你想开发潜行类游戏时,那么这款视觉插件非 ...

  5. sequelize关联相关表

    在article的迁移文件: 在commemt里面添加: 在单条查询里面 这样一个文章里面包含一个评论

  6. 写一些Linux文件夹操作的一些感悟。

    rwx 权限 对目录的作用 读权限(r) 表示具有读取目录结构列表的权限,也就是说,可以看到目录中有哪些文件和子目录.一旦对目录拥有 r 权限,就可以在此目录下执行 ls 命令,查看目录中的内容. 写 ...

  7. Loadrunner录制时弹出Microsoft Visual C++ Runtime Library解决方案

    这段时间用loadrunner测试工具,录制脚本的时候老是出现这个弹窗,刚开始就以为是软件错误,就用的软件修复,也解决了,后来还是出现这样的错误,修复也没有用 原因:可能是代理服务器在调用VC库的时候 ...

  8. 5、Excel—在做车辆费用汇总的时候,复制出来的数据跟同事的一样,但是合计总数就不一样

    在做车辆费用汇总的时候,复制出来的数据跟同事的一样,但是合计总数就不一样, 刚开始以为是数值问题,明明两份Excel都是同样的数据,为什么合计就不一样呢?(根据同事那份的数据,然后手动在自己的exce ...

  9. OO课程第一阶段(前三次作业)总结Blog1

    OO课程第一阶段(前三次作业)总结Blog1 前言:学习OOP课程的第一阶段已经结束了,在此进行对于知识点,题量,难度的个人看法. (1)相比于另外两次作业,第一次作业基本上是基本的编程的语法训练,题 ...

  10. 如何跳出forEach循环

    for(let ii in this.listData){ console.log("提交前数据",ii) try{ this.listData[ii].forEach((el,i ...