更多内容,前往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. 常用的js优秀框架个人记录

    一.树框架 zTree http://www.treejs.cn/

  2. node.js发送短信验证码(附带60秒倒计时插件)

    推荐一个简单且功能齐全的发送短信验证码接口1.安装下载后的SDK只包含一个zhenzisms.js文件,直接导入到工程中即可使用.下载 2.用法引入模块 const zhenzismsClient = ...

  3. Java 基础(二)

    类的初始 类中包括:属性,方法. 快速使用 我们都是人,而人的共同特点有很多. 比如:名字,年龄,性别,吃饭,睡觉... // 定义类 public class Person { // 定义属性 St ...

  4. Vue3父组件调用子组件内部的方法

    1. 子组件中定义方法并通过defineExpose暴露出去 import { reactive, defineExpose } from "vue"; const state = ...

  5. linux分区增加硬盘空间

    https://blog.csdn.net/netgc/article/details/119978449

  6. 3月1日Android开学学习

    Android开发的简单控件 1.文本显示 2.视图基础 3.常用布局 4.按钮触控 5.图像显示 文本显示 (1)设置文本内容 1.在XML文件中通过属性Android:text设置文本 Andro ...

  7. vue2项目引入新版ant-design-vue报错问题

    vue2项目引入3.2.14版ant-design-vue会报1600多个编译错误,纯属版本问题,但3.2.14版本卸载会出错,需要删除项目重建,重建后搜索依赖ant-design-vue-fixed ...

  8. Linux_MySQL

    MySQL 安装 AB复制 安装 1.编译安装 2.yum安装 [https://www.mysql.com/] yum安装的方式 1.在官网下载mysql rpm包 # wget https://d ...

  9. v-show无法隐藏自定义组件

    因为v-show的本质是设置标签display:none,但组件并非是一个标签,所以无法使用v-show控制组件 错误用法: 正确用法:

  10. 构建 Maven 项目卡爆?优化后:1 秒完成…

    在实际开发中,我们通常会用到maven的archetype插件(原型框架)来生成项目框架. 但是无奈,创建时,总会卡在: [INFO] Generating project in Batch mode ...