Spring Security 入门原理及实战
2020-12-13 14:36
标签:static pen otf 模式 blog 用户角色 策略 input override 参考博客: https://www.cnblogs.com/demingblog/p/10874753.html Spring Security 是spring项目之中的一个安全模块,可以非常方便与spring项目无缝集成。 特别是在spring boot项目中加入spring security更是十分简单, 这里就简单介绍一下入门案例和使用原理吧! 写一个简单的springboot测试例子: 在springboot中的pom.xml中引入springsecurity, 加入如下代码: 然后在配置文件中写入 spring security 默认提供了表单登录的功能。我们新建一个类 上面的代码其实就是 一种配置,authorizeRequests() 定义哪些URL需要被保护、哪些不需要被保护。 formLogin() 定义当需要用户登录时候,转到的登录页面。 此时,我们并没有写登录页面,但是spring security默认提供了一个登录页面,以及登录控制器。我们这里简单写一个自定义的登录页面: 我们可以发现,这里有个form 。 再配置文件加入如下: 重启项目,访问被保护的/hello页面。自动跳转到了spring security 默认的登录页面,我们输入用户名admin密码admin。点击 除了登录,spring security还提供了rememberMe功能,这里不做过多解释 通常情况下,我们需要实现“特定资源只能由特定角色访问”的功能。假设我们的系统有如下两个角色: 现在我们给系统增加“/product” 代表商品信息方面的资源(USER可以访问);增加"/admin"代码管理员方面的资源(USER不能访问)。代码如下: 通过上面的配置, 可以简单实现一个springsecurity的小例子. 下面说一下springsecurity的原理: spring security核心组件有:SecurityContext、SecurityContextHolder、Authentication、Userdetails 和 AuthenticationManager,下面分别介绍。 SecurityContext 安全上下文,用户通过Spring Security 的校验之后,验证信息存储在SecurityContext中,SecurityContext的接口定义如下: authentication 直译过来是“认证”的意思,在Spring Security 中Authentication用来表示当前用户是谁,一般来讲你可以理解为authentication就是一组用户名密码信息。Authentication也是一个接口,其定义如下: 接口有4个get方法,分别获取 因此可以推断其实现类有这4个属性。这几个方法作用如下: UserDetails,看命知义,是用户信息的意思。其存储的就是用户信息,其定义如下: 方法含义如下: 提到了 通常在spring security应用中,我们会自定义一个CustomUserDetailsService来实现UserDetailsService接口,并实现其 我们在实现 (通常是一个 在实现 这个异常是 AuthenticationManager 是一个接口,它只有一个方法,接收参数为 AuthenticationManager 的作用就是校验 因此代码逻辑并不能实例化一个AuthenticationException异常并抛出,实际上抛出的异常通常是其实现类,如 总结: SpringSecurity是个非常不错的框架,是个颗粒级别的验证框架,和springboot融合的非常完美, 值得学习。 https://www.cnblogs.com/demingblog/p/10874753.html 这篇博客写的非常清楚, 把原理分析的比较透彻, 可以接着学习底层的东西多一点。 Spring Security 入门原理及实战 标签:static pen otf 模式 blog 用户角色 策略 input override 原文地址:https://www.cnblogs.com/xumBlog/p/11565973.html@Controller
public class AppController {
@RequestMapping("/hello")
@ResponseBody
String home() {
return "Hello ,spring security!";
}
}
dependency>
groupId>org.springframework.bootgroupId>
artifactId>spring-boot-starter-securityartifactId>
dependency>
security.basic.enabled=false
SecurityConfiguration
,并加入一些代码,如下所示:@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().and()
.httpBasic();
}
}
html>head>title>Login Pagetitle>head>body onload=‘document.f.username.focus();‘>
h3>Login with Username and Passwordh3>form name=‘f‘ action=‘/login‘ method=‘POST‘>
table>
tr>td>User:td>td>input type=‘text‘ name=‘username‘ value=‘‘>td>tr>
tr>td>Password:td>td>input type=‘password‘ name=‘password‘/>td>tr>
tr>td colspan=‘2‘>input name="submit" type="submit" value="Login"/>td>tr>
input name="_csrf" type="hidden" value="635780a5-6853-4fcd-ba14-77db85dbd8bd" />
table>
form>body>html>
action="/login"
,这个/login
依然是spring security
提供的。form表单提交了三个数据:
security.user.name=admin
security.user.password=admin
Login
按钮。会发现登录成功并跳转到了/hello。
@Controller
@RequestMapping("/product")
public class ProductTestController {
@RequestMapping("/info")
@ResponseBody
public String productInfo(){
return " some product info ";
}
}
-------------------------------------------
@Controller
@RequestMapping("/admin")
public class AdminTestController {
@RequestMapping("/home")
@ResponseBody
public String productInfo(){
return " admin home page ";
}
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("admin1") // 管理员,同事具有 ADMIN,USER权限,可以访问所有资源
.password("admin1")
.roles("ADMIN", "USER")
.and()
.withUser("user1").password("user1") // 普通用户,只能访问 /product/**
.roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/product/**").hasRole("USER")
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin().and()
.httpBasic();
}
Spring Security的核心组件
public interface SecurityContext extends Serializable {
/**
* Obtains the currently authenticated principal, or an authentication request token.
*
* @return the
Authentication
or null
if no authentication
* information is available
*/
Authentication getAuthentication();
/**
* Changes the currently authenticated principal, or removes the authentication
* information.
*
* @param authentication the new Authentication
token, or
* null
if no further authentication information should be stored
*/
void setAuthentication(Authentication authentication);
}SecurityContextHolder
SecurityContextHolder看名知义,是一个holder,用来hold住SecurityContext实例的。其作用就是存储当前认证信息。
在典型的web应用程序中,用户登录一次,然后由其会话ID标识。服务器缓存持续时间会话的主体信息。
在Spring Security中,在请求之间存储SecurityContext的责任落在SecurityContextPersistenceFilter上,
默认情况下,该上下文将上下文存储为HTTP请求之间的HttpSession属性。
它会为每个请求恢复上下文SecurityContextHolder,并且最重要的是,在请求完成时清除SecurityContextHolder。
SecurityContextHolder是一个类,他的功能方法都是静态的(static)。
SecurityContextHolder可以设置指定JVM策略(SecurityContext的存储策略),这个策略有三种:
1. MODE_THREADLOCAL:SecurityContext 存储在线程中。
2. MODE_INHERITABLETHREADLOCAL:SecurityContext 存储在线程中,但子线程可以获取到父线程中的 SecurityContext。
3. MODE_GLOBAL:SecurityContext 在所有线程中都相同。
SecurityContextHolder默认使用MODE_THREADLOCAL模式,即存储在当前线程中。在spring security应用中,我们通常能看到类似如下的代码:
SecurityContextHolder.getContext().setAuthentication(token);
Authentication
public interface Authentication extends Principal, Serializable {
Collection extends GrantedAuthority> getAuthorities();
Object getCredentials();
Object getDetails();
Object getPrincipal();
boolean isAuthenticated();
void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
}
Authorities
, 填充的是用户角色信息。
Credentials
,直译,证书。填充的是密码。
Details
,用户信息。
Principal
直译,形容词是“主要的,最重要的”,名词是“负责人,资本,本金”。感觉很别扭,所以,还是不翻译了,直接用原词principal来表示这个概念,其填充的是用户名。
getAuthorities
: 获取用户权限,一般情况下获取到的是用户的角色信息。
getCredentials
: 获取证明用户认证的信息,通常情况下获取到的是密码等信息。
getDetails
: 获取用户的额外信息,(这部分信息可以是我们的用户表中的信息)
getPrincipal
: 获取用户身份信息,在未认证的情况下获取到的是用户名,在已认证的情况下获取到的是 UserDetails (UserDetails也是一个接口,里边的方法有getUsername,getPassword等)。
isAuthenticated
: 获取当前 Authentication 是否已认证。
setAuthenticated
: 设置当前 Authentication 是否已认证(true or false)。UserDetails
public interface UserDetails extends Serializable {
Collection extends GrantedAuthority> getAuthorities();
String getPassword();
String getUsername();
boolean isAccountNonExpired();
boolean isAccountNonLocked();
boolean isCredentialsNonExpired();
boolean isEnabled();
}
getAuthorites
:获取用户权限,本质上是用户的角色信息。
getPassword
: 获取密码。
getUserName
: 获取用户名。
isAccountNonExpired
: 账户是否过期。
isAccountNonLocked
: 账户是否被锁定。
isCredentialsNonExpired
: 密码是否过期。
isEnabled
: 账户是否可用。UserDetailsService
UserDetails
就必须得提到UserDetailsService
, UserDetailsService也是一个接口,且只有一个方法loadUserByUsername
,他可以用来获取UserDetails。public UserDetails loadUserByUsername(final String login);
方法。loadUserByUsername
方法的时候,就可以通过查询数据库(或者是缓存、或者是其他的存储形式)来获取用户信息,然后组装成一个UserDetails
,org.springframework.security.core.userdetails.User
,它继承自UserDetails) 并返回。loadUserByUsername
方法的时候,如果我们通过查库没有查到相关记录,需要抛出一个异常来告诉spring security来“善后”。org.springframework.security.core.userdetails.UsernameNotFoundException
。AuthenticationManager
Authentication
,其定义如下:public interface AuthenticationManager {
Authentication authenticate(Authentication authentication)
throws AuthenticationException;
}
Authentication
,如果验证失败会抛出AuthenticationException
异常。AuthenticationException
是一个抽象类,DisabledException
,LockedException
,BadCredentialsException
等。BadCredentialsException
可能会比较常见,即密码错误的时候。