优质博文:IT-BLOG-CN
一、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
目录,如下:
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 : 定义用户角色,需要实现的接口
ListGrantedAuthority> 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 对象获取
☏ SecurityContextHolder
用于存储安全上下文security context
的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保存在SecurityContextHolder
中。SecurityContextHolder
默认使用ThreadLocal
策略来存储认证信息。看到ThreadLocal
也就意味着,这是一种与线程绑定的策略。Spring Security
在用户登录时自动绑定认证信息到当前线程,在用户退出时,自动清除当前线程的认证信息。但这一切的前提,是你在web
场景下使用Spring Security
。
☏ 因为身份信息是与线程绑定的,所以可以在程序的任何地方使用静态方法获取用户信息。一个典型的获取当前登录用户的姓名的例子如下所示:getAuthentication()
返回了认证信息。
@RequestMapping("/name")
public MapString, String> getName(){
//获取登录名
String name = SecurityContextHolder.getContext().getAuthentication().getName();
MapString, String> map = new HashMap>();
map.put("loginName", name);
return map;
}
☏ Authentication
源码:
package org.springframework.security.core;//
public interface Authentication extends Principal, Serializable { //
Collection? extends GrantedAuthority> getAuthorities(); //
Object getCredentials();//
Object getDetails();//
Object getPrincipal();//
boolean isAuthenticated();//
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
接口的实现类,也是框架中的常用接口之一。