优质博文:IT-BLOG-CN
Spring Security
是一个能够为基于Spring
的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring
应用上下文中配置的 Bean,充分利用了Spring IoC
,DI
(控制反转 Inversion of Control
,DI
:Dependency Injection
依赖注入)和AOP
(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
【1】创建Maven
工程(war
形式):spring-security-demo
【2】修改pom.xml
目录,如下:
<properties>
<junit.version>4.12junit.version>
<spring.version>4.2.4.RELEASEspring.version>
<pagehelper.version>4.0.0pagehelper.version>
<servlet-api.version>2.5servlet-api.version>
<dubbo.version>2.8.4dubbo.version>
<zookeeper.version>3.4.7zookeeper.version>
<zkclient.version>0.1zkclient.version>
<mybatis.version>3.2.8mybatis.version>
<mybatis.spring.version>1.2.2mybatis.spring.version>
<mybatis.paginator.version>1.2.15mybatis.paginator.version>
<mysql.version>5.1.32mysql.version>
<druid.version>1.0.9druid.version>
<commons-fileupload.version>1.3.1commons-fileupload.version>
<freemarker.version>2.3.23freemarker.version>
<activemq.version>5.11.2activemq.version>
<security.version>3.2.3.RELEASEsecurity.version>
<solrj.version>4.10.3solrj.version>
<ik.version>2012_u6ik.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-coreartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-context-supportartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframework.securitygroupId>
<artifactId>spring-security-webartifactId>
<version>4.1.0.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframework.securitygroupId>
<artifactId>spring-security-configartifactId>
<version>4.1.0.RELEASEversion>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>servlet-apiartifactId>
<version>2.5version>
<scope>providedscope>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<version>3.2version>
<configuration>
<source>1.7source>
<target>1.7target>
<encoding>UTF-8encoding>
configuration>
plugin>
<plugin>
<groupId>org.apache.tomcat.mavengroupId>
<artifactId>tomcat7-maven-pluginartifactId>
<configuration>
<port>9090port>
<path>/path>
configuration>
plugin>
plugins>
build>
注意:如果只是给自己的项目中嵌入Spring Security
安全框架,只需要添加如下两个jar
包即可。
<dependency>
<groupId>org.springframework.securitygroupId>
<artifactId>spring-security-webartifactId>
<version>4.1.0.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframework.securitygroupId>
<artifactId>spring-security-configartifactId>
<version>4.1.0.RELEASEversion>
dependency>
【3】创建web.xml
文件(通过Spring Security
拦截需要处理的请求和引入Spring Security
的配置文件)。
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<context-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:spring-security.xmlparam-value>
context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
listener-class>
listener>
<filter>
<filter-name>springSecurityFilterChainfilter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxyfilter-class>
filter>
<filter-mapping>
<filter-name>springSecurityFilterChainfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
web-app>
【4】创建Spring Security
配置文件:spring-security.xml
(与 web.xml
中引入的配置文件对应),代码中有配置的详细说明注解。
<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 use-expressions="false">
<intercept-url pattern="/**" access="ROLE_SELLER" />
<form-login login-page="/login.html"
default-target-url="/index.html"
authentication-failure-url="/login_error.html"
always-use-default-target="true" />
<csrf disabled="true" />
<headers>
<frame-options policy="SAMEORIGIN" />
headers>
<logout />
http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="admin" password="123456" authorities="ROLE_USER"/>
user-service>
authentication-provider>
authentication-manager>
beans:beans>
【5】需要自己创建:login.html
(登录页面 如下)、index.html
(登录成功跳转页面)、login_error.html
(登录失败跳转页面)
DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登陆title>
head>
<body>
--欢迎登陆我的系统--
<form action="/login" method="post">
用户名:<input name="username"><br>
密码:<input name="password"><br>
<button>登陆button>
form>
body>
html>
【1】配置文件中配置的,登录时用户名和密码的业务逻辑处理类(实现UserDetailsService
:框架自带的接口),注意:普通demo
不需要此部分,主要用于真是环境登录逻辑的处理。
public class UserDetailServiceImpl implements UserDetailsService {
//当通过配置文件的形式,引入服务类时需要设置set方法。
private SellerService sellerService;
public void setSellerService(SellerService sellerService) {
this.sellerService = sellerService;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//GrantedAuthority : 定义用户角色,需要实现的接口
List<GrantedAuthority> list =new ArrayList<>();
//用户添加角色,SimpleGrantedAuthority可以定义用户角色,实现了GrantedAuthority接口,
//格式必须以(ROLE_)开头
list.add(new SimpleGrantedAuthority("ROLE_SELLER"));
//从数据库中获取用户信息。
TbSeller seller = sellerService.findOne(username);
if(seller != null) {
//返回username:传过来的参数。seller.getPassword:数据库中获取到的用户密码。
//list:用户的所有角色,可以从数据库中获取
return new User(username, seller.getPassword(), list);
}else {
return null;
}
}
}
【2】BCrypt
加密过程(配置中说明了BCrypt
与MD5
的区别)。
@RequestMapping("/add")
public Result add(@RequestBody TbSeller seller){
try {
//BCrypt加密使用的对象BCryptPasswordEncoder
BCryptPasswordEncoder cryptPasswordEncoder = new BCryptPasswordEncoder();
//使用encode方法对传入的密码加密,返回30位的字符串
String encode = cryptPasswordEncoder.encode(seller.getPassword());
//业务处理:接入对象中
seller.setPassword(encode);
//调用服务层,入库
sellerService.add(seller);
return new Result(true, "增加成功");
} catch (Exception e) {
e.printStackTrace();
return new Result(false, "增加失败");
}
}
☏ SecurityContextHolder
用于存储安全上下文security context
的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保存在SecurityContextHolder
中。SecurityContextHolder
默认使用ThreadLocal
策略来存储认证信息。看到ThreadLocal
也就意味着,这是一种与线程绑定的策略。Spring Security
在用户登录时自动绑定认证信息到当前线程,在用户退出时,自动清除当前线程的认证信息。但这一切的前提,是你在web
场景下使用Spring Security
。
☏ 因为身份信息是与线程绑定的,所以可以在程序的任何地方使用静态方法获取用户信息。一个典型的获取当前登录用户的姓名的例子如下所示:getAuthentication()
返回了认证信息。
@RequestMapping("/name")
public Map<String, String> getName(){
//获取登录名
String name = SecurityContextHolder.getContext().getAuthentication().getName();
Map<String, String> map = new HashMap<>();
map.put("loginName", name);
return map;
}
☏ Authentication
源码:
package org.springframework.security.core;// <1>
public interface Authentication extends Principal, Serializable { // <1>
Collection<? extends GrantedAuthority> getAuthorities(); // <2>
Object getCredentials();// <2>
Object getDetails();// <2>
Object getPrincipal();// <2>
boolean isAuthenticated();// <2>
void setAuthenticated(boolean var1) throws IllegalArgumentException;
}
【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
接口的实现类,也是框架中的常用接口之一。