spring security使用和原理简析(2)

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

框架用来实现登录的功能

待明确源码

扫描二维码关注公众号,回复: 6581733 查看本文章

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.springframework.security.authentication.UsernamePasswordAuthenticationToken@441d0230:
Principal: pjmike; 
Credentials: [PROTECTED];
Authenticated: true; Details: null; 
Granted Authorities: ROLE_USER
View Code

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

猜你喜欢

转载自www.cnblogs.com/jiataoq/p/11073683.html