springsecurity的原理及教程解析

TheDisguiser 2020-08-07 18:52:00 java常见问答 5492

关于springsecurity的原理上次小伙伴们都已经粗略了解了下,本篇本站小编将带大家深入了解springsecurity的各种方法原理及实现,快来看看吧。

原理

核心组件:

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

安全上下文,用户通过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);

UserDetails

public interface UserDetails extends Serializable
{
    Collection < ? extends GrantedAuthority > getAuthorities();
    String getPassword();
    String getUsername();
    boolean isAccountNonExpired();
    boolean isAccountNonLocked();
    boolean isCredentialsNonExpired();
    boolean isEnabled();
}

UserDetails名为用户信息。存储的就是用户信息,定义如下:

public interface UserDetails extends Serializable
{
    Collection < ? extends GrantedAuthority > getAuthorities();
    String getPassword();
    String getUsername();
    boolean isAccountNonExpired();
    boolean isAccountNonLocked();
    boolean isCredentialsNonExpired();
    boolean isEnabled();
}

AuthenticationManager

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

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

Authentication

名为“认证”的意思,在Spring Security 中用来表示当前用户是谁,可以理解为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;
}

实现:

一个简单的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();
    }
}

编写简单登录页面

<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>

再加入配置文件:

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

现在我们给系统增加“/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 ";
    }
}

以上就是本篇文章的所有内容,小伙伴们还有什么不懂得吗?还有关于java架构师的疑问的话,请记得来本网站查找答案。

推荐阅读:

springsecurity权限控制的原理是如何实现的?

springsecurity两套登陆规则是什么?springsecurity详解