Spring Security 入门原理及实战

参考博客: https://www.cnblogs.com/demingblog/p/10874753.html

Spring Security 是spring项目之中的一个安全模块,可以非常方便与spring项目无缝集成。

特别是在spring boot项目中加入spring security更是十分简单, 这里就简单介绍一下入门案例和使用原理吧!

写一个简单的springboot测试例子:

@Controller
public class AppController {

    @RequestMapping("/hello")
    @ResponseBody
    String home() {
        return "Hello ,spring security!";
    }
}

在springboot中的pom.xml中引入springsecurity, 加入如下代码:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

然后在配置文件中写入

security.basic.enabled=false

spring security 默认提供了表单登录的功能。我们新建一个类SecurityConfiguration,并加入一些代码,如下所示:

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
            http
                .authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .formLogin().and()
                .httpBasic();
    }
}

上面的代码其实就是 一种配置,authorizeRequests() 定义哪些URL需要被保护、哪些不需要被保护。 formLogin() 定义当需要用户登录时候,转到的登录页面。

此时,我们并没有写登录页面,但是spring security默认提供了一个登录页面,以及登录控制器。我们这里简单写一个自定义的登录页面:

<html><head><title>Login Page</title></head><body onload=‘document.f.username.focus();‘>
<h3>Login with Username and Password</h3><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>

我们可以发现,这里有个form 。action="/login",这个/login依然是spring security提供的。form表单提交了三个数据:

  • username 用户名

  • password 密码
  • _csrf CSRF保护方面的内容,暂时先不展开解释

再配置文件加入如下:

security.user.name=admin
security.user.password=admin

重启项目,访问被保护的/hello页面。自动跳转到了spring security 默认的登录页面,我们输入用户名admin密码admin。点击Login按钮。会发现登录成功并跳转到了/hello。

除了登录,spring security还提供了rememberMe功能,这里不做过多解释

通常情况下,我们需要实现“特定资源只能由特定角色访问”的功能。假设我们的系统有如下两个角色:

  • ADMIN 可以访问所有资源

  • USER 只能访问特定资源

现在我们给系统增加“/product” 代表商品信息方面的资源(USER可以访问);增加"/admin"代码管理员方面的资源(USER不能访问)。代码如下:

@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();
    }

通过上面的配置, 可以简单实现一个springsecurity的小例子. 下面说一下springsecurity的原理:

Spring Security的核心组件

spring security核心组件有:SecurityContext、SecurityContextHolder、Authentication、Userdetails 和 AuthenticationManager,下面分别介绍。

SecurityContext

安全上下文,用户通过Spring Security 的校验之后,验证信息存储在SecurityContext中,SecurityContext的接口定义如下:

public interface SecurityContext extends Serializable {
    /**
     * Obtains the currently authenticated principal, or an authentication request token.
     *
     * @return the <code>Authentication</code> or <code>null</code> if no authentication
     * information is available
     */
    Authentication getAuthentication();

    /**
     * Changes the currently authenticated principal, or removes the authentication
     * information.
     *
     * @param authentication the new <code>Authentication</code> token, or
     * <code>null</code> 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

authentication 直译过来是“认证”的意思,在Spring Security 中Authentication用来表示当前用户是谁,一般来讲你可以理解为authentication就是一组用户名密码信息。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;
}

接口有4个get方法,分别获取

  • Authorities, 填充的是用户角色信息。

  • Credentials,直译,证书。填充的是密码。
  • Details ,用户信息。
  • Principal 直译,形容词是“主要的,最重要的”,名词是“负责人,资本,本金”。感觉很别扭,所以,还是不翻译了,直接用原词principal来表示这个概念,其填充的是用户名。

因此可以推断其实现类有这4个属性。这几个方法作用如下:

  • getAuthorities: 获取用户权限,一般情况下获取到的是用户的角色信息。

  • getCredentials: 获取证明用户认证的信息,通常情况下获取到的是密码等信息。
  • getDetails: 获取用户的额外信息,(这部分信息可以是我们的用户表中的信息)
  • getPrincipal: 获取用户身份信息,在未认证的情况下获取到的是用户名,在已认证的情况下获取到的是 UserDetails (UserDetails也是一个接口,里边的方法有getUsername,getPassword等)。
  • isAuthenticated: 获取当前 Authentication 是否已认证。
  • setAuthenticated: 设置当前 Authentication 是否已认证(true or false)。

UserDetails

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。

通常在spring security应用中,我们会自定义一个CustomUserDetailsService来实现UserDetailsService接口,并实现其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

AuthenticationManager 是一个接口,它只有一个方法,接收参数为Authentication,其定义如下:

public interface AuthenticationManager {
    Authentication authenticate(Authentication authentication)
            throws AuthenticationException;
}

AuthenticationManager 的作用就是校验Authentication,如果验证失败会抛出AuthenticationException异常。AuthenticationException是一个抽象类,

因此代码逻辑并不能实例化一个AuthenticationException异常并抛出,实际上抛出的异常通常是其实现类,如DisabledException,LockedException,BadCredentialsException等。

BadCredentialsException可能会比较常见,即密码错误的时候。

总结:

SpringSecurity是个非常不错的框架,是个颗粒级别的验证框架,和springboot融合的非常完美, 值得学习。

https://www.cnblogs.com/demingblog/p/10874753.html  这篇博客写的非常清楚, 把原理分析的比较透彻, 可以接着学习底层的东西多一点。

原文地址:https://www.cnblogs.com/xumBlog/p/11565973.html

时间: 2024-11-11 17:34:55

Spring Security 入门原理及实战的相关文章

Spring Security入门

Spring Security入门: http://www.mossle.com/docs/auth/html/index.html Spring Security 默认的过滤器链 https://blog.csdn.net/u013421749/article/details/78626275 原文地址:https://www.cnblogs.com/aligege/p/9396278.html

Spring Security 入门(三)

在说完了Spring Security框架的功能和执行流程后,就到了写它Spring Boot的集成,先来看最简的配置: <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.6.RELEASE</version> </parent>

Spring Security 入门(二)

Spring Security 入门(一)中说到,Spring Security执行流程第一步是容器启动时加载系统资源与权限列表,第二步是WEB容器启动时加载拦截器链,并介绍了自定义拦截器的方法.接下来第三步步就是用户登录.介绍下用户登录的流程: 获取用户名和密码,并放入一个 UsernamePasswordAuthenticationToken 实例中(Authentication接口的一个实例); 这个token被传递到一个 AuthenticationManager 实例中进行验证; 若验

Spring Security入门(2-2)Spring Security 的运行原理 2

Java配置和表单登录 因此使用Java代码配置Spring Security主要是这两个步骤:1.创建过滤器2.注册过滤器. 1.创建过滤器这段配置创建一个Servlet Filter:springSecurityFilterChain,其负责应用中的所有安全,包括:保护应用的URLS,验证提交的username和password,重定向到登录页面等. 通过以下代码可以看到使用Java配置Spring Security的基础案例: @EnableWebSecuritypublic class

Spring Security 入门(一)

当你看到这篇文章时,我猜你肯定是碰到令人苦恼的问题了,我希望本文能让你有所收获. 本人几个月前还是 Spring 小白,几个月走来,看了 Spring,Spring boot,到这次的 Spring Security. 为了避免大家踩坑,本人将入门的经验传授给那些和我一样正在学习 Spring Security 的小白. 我们从官方例子学习起: 1.我们先来创建一个 Spring Boot 的项目 HelloWorld: 我用的开发工具是 eclipse,如果没装 STS 的话,请点击 Help

Spring Security 入门(1-3)Spring Security oauth2.0 指南

入门 这是支持OAuth2.0的用户指南.对于OAuth1.0,一切都是不同的,所以看它的用户指南. 本用户指南分为两个部分,第一部分是OAuth2.0提供端(OAuth 2.0 Provider),第二部分是OAuth2.0的客户端(OAuth 2.0 Client) OAuth2.0提供端 OAuth2.0的提供端的用途是负责将受保护的资源暴露出去.建立一个可以访问受保护的资源的客户端列表. 提供端是通过管理和验证可用于访问受保护的资源的OAuth 2令牌来做的. 在适当的地方,提供端必须为

Spring Security 入门(1-14)Spring Security 开发指南(转)

开发指南:http://www.cnblogs.com/xingxueliao/p/5911292.html Spring OAuth2.0 提供者实现原理: Spring OAuth2.0提供者实际上分为: 授权服务 Authorization Service. 资源服务 Resource Service. 虽然这两个提供者有时候可能存在同一个应用程序中,但在Spring Security OAuth中你可以把 他它们各自放在不同的应用上,而且你可以有多个资源服务,它们共享同一个中央授权服 务

Spring Security 入门详解

序:本文主要参考 spring实战 对里面的知识做一个梳理 1.Spring Security介绍 Spring Security是基于spring的应用程序提供声明式安全保护的安全性框架,它提供了完整的安全性解决方案,能够在web请求级别和方法调用级别处理身份证验证和授权.它充分使用了依赖注入和面向切面的技术. Spring security主要是从两个方面解决安全性问题: web请求级别:使用servlet过滤器保护web请求并限制URL级别的访问 方法调用级别:使用Spring AOP保护

[转]spring security的原理及教程

Authentication:认证     spring security使用分类: 如何使用spring security,相信百度过的都知道,总共有四种用法,从简到深为:1.不用数据库,全部数据写在配置文件,这个也是官方文档里面的demo:2.使用 数据库,根据spring security默认实现代码设计数据库,也就是说数据库已经固定了,这种方法不灵活,而且那个数据库设计得很简陋,实用性差:3.spring security和Acegi不同,它不能修改默认filter了,但支持插入filt