spring security使用和原理简析

Posted jiataoq

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring security使用和原理简析相关的知识,希望对你有一定的参考价值。

转自https://pjmike.github.io/2018/10/12/%E6%B5%85%E6%9E%90Spring-Security-%E6%A0%B8%E5%BF%83%E7%BB%84%E4%BB%B6/

上一篇我们主要讲述了如何搭项目,这里我们就来简单探究一下原理

 

Spring Security的核心类

Spring Security的核心类主要包括以下几个:

  • SecurityContextHolder: 存放身份信息的容器
  • Authentication: 身份信息的抽象接口
  • AuthenticationManager: 身份认证器,认证的核心接口
  • UserDetailsService: 一般用于从数据库中加载身份信息
  • UserDetails: 相比Authentication,有更详细的身份信息

SecurityContextHolder、Securityontext和Authentication

SecurityContextHolder用于存储安全上下文(security context)的信息,即一个存储身份信息,认证信息等的容器。SecurityContextHolder默认使用 ThreadLocal策略来存储认证信息,即一种与线程绑定的策略,每个线程执行时都可以获取该线程中的 安全上下文(security context),各个线程中的安全上下文互不影响。而且如果说要在请求结束后清除安全上下文中的信息,利用该策略Spring Security也可以轻松搞定。

因为身份信息时与线程绑定的,所以我们可以在程序的任何地方使用静态方法获取用户信息,一个获取当前登录用户的姓名的例子如下:

技术图片
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();

if (principal instanceof UserDetails) 
String username = ((UserDetails)principal).getUsername();
 else 
String username = principal.toString();
View Code

 

getAuthentication()方法返回了认证信息,准确的说是一个 Authentication实例,Authentication是 Spring Security 中的一个重要接口,直接继承自 Principal类,该接口表示对用户身份信息的抽象,接口源码如下:

技术图片
public interface Authentication extends Principal, Serializable  
    //权限信息列表,默认是 GrantedAuthority接口的一些实现
    Collection<? extends GrantedAuthority> getAuthorities(); 
    //密码信息,用户输入的密码字符串,认证后通常会被移除,用于保证安全
    Object getCredentials();
    //细节信息,web应用中通常的接口为 WebAuthenticationDetails,它记录了访问者的ip地址和sessionId的值
    Object getDetails();
    //身份信息,返回UserDetails的实现类
    Object getPrincipal();
    //认证状态,默认为false,认证成功后为 true
    boolean isAuthenticated();
    //上述身份信息是否经过身份认证 
    void setAuthenticated(boolean var1) throws IllegalArgumentException;
View Code

 

AuthenticationManager、ProviderManager 和 AuthenticationProvider

框架用来实现登录的功能

待明确源码

UserDetailsService 和 UserDetails

UserDetailsService简单说就是加载对应的UserDetails的接口(一般从数据库),而UserDetails包含了更详细的用户信息,定义如下:

技术图片
public interface UserDetails extends Serializable 

   Collection<? extends GrantedAuthority> getAuthorities();

   String getPassword();

   String getUsername();

   boolean isAccountNonExpired();

   boolean isAccountNonLocked();

   boolean isCredentialsNonExpired();

   boolean isEnabled();
View Code

UserDetails 接口与 Authentication接口相似,它们都有 username、authorities。它们的区别如下:

  • Authentication 的 getCredentials() 与 UserDetails 中的 getPassword() 不一样,前者是用户提交的密码凭证,后者是用户正确的密码,(一般是从数据库中载入的密码),AuthenticationProvider就会对两者进行对比。
  • Authentication 中的 getAuthorities() 实际上是由 UserDetails 的 getAuthorities()传递形成的。
  • Authentication 中的 getUserDetails() 中的 UserDetails 用户详细信息时经过 AuthenticationProvider认证之后填充的。

认证过程的官方样例

技术图片
public class SpringSecuriryTestDemo 
    private static AuthenticationManager am = new SampleAuthenticationManager();

    public static void main(String[] args) throws IOException 
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        while (true) 
            System.out.println("Please enter your username:");
            String name = in.readLine();
            System.out.println("Please enter your password:");
            String password = in.readLine();
            try 
                Authentication request = new UsernamePasswordAuthenticationToken(name, password);
                Authentication result = am.authenticate(request);
                SecurityContextHolder.getContext().setAuthentication(request);
                break;
             catch (AuthenticationException e) 
                System.out.println("Authentication failed: " + e.getMessage());
            
        
        System.out.println("Successfully authenticated. Security context contains: " + SecurityContextHolder.getContext().getAuthentication());
    
    static class SampleAuthenticationManager implements AuthenticationManager 
        static final List<GrantedAuthority> AUTHORITIES = new ArrayList<GrantedAuthority>();
        static 
            AUTHORITIES.add(new SimpleGrantedAuthority("ROLE_USER"));
        
        @Override
        public Authentication authenticate(Authentication authentication) throws AuthenticationException 
            if (authentication.getName().equals(authentication.getCredentials())) 
                return new UsernamePasswordAuthenticationToken(authentication.getName(), authentication.getCredentials(), AUTHORITIES);
            
            throw new BadCredentialsException("Bad Credentials");
        
    
View Code

 

结果

技术图片
Please enter your username:
pjmike
Please enter your password:
123
Authentication failed: Bad Credentials
Please enter your username:
pjmike
Please enter your password:
pjmike
Successfully authenticated. 
Security context contains: org.springframew[email protected]441d0230:
Principal: pjmike; 
Credentials: [PROTECTED];
Authenticated: true; Details: null; 
Granted Authorities: ROLE_USER
View Code

 

了解了简单的认证过程,下一篇在看一下spring security的filter chain

以上是关于spring security使用和原理简析的主要内容,如果未能解决你的问题,请参考以下文章

Spring Security sec:使用 Java Config 授权标签

如何在 Spring Security thymeleaf sec 中使用列表:授权标签

Spring Security sec:授权抛出异常

Spring Security - Thymeleaf - 我可以在 sec:authorize 标签中评估 SPEL 表达式吗?

sec:authorize 对 Spring Security 不起作用

我在这里使用 Struts 2 和 Spring Security Integration