认证过程分析:
1.用户提交用户名 密码被 SecurityFilterChain 中的UsernamePasswordAuthenticationFilter 过滤器获取到, 封装为请求Authentication ,通常情况下是UsernamePasswordAuthenticationToken这个实现类。
2.然后过滤器将Authentication提交至认证管理器(AuthenticationManager)进行认证
3.认证成功后,AuthenticationManager身份管理器返回一个被填充满了信息的(包括上面提到的权限信息, 身份信息,细节信息,但密码通常会被移除)Authentication实例。
4.SecurityContextHolder安全上下文容器将第3步填充了信息的Authentication ,通过 SecurityContextHolder.getContext().setAuthentication(…)方法,设置到其中。
可以看出AuthenticationManager接口(认证管理器)是认证相关的核心接口 ,也是发起认证的出发点,它的实现类为ProviderManager。而SpringSecurity支持多种认证方式,因此ProviderManager维护着一个List
列表,存放多种认证方式,最终实际的认证工作是由AuthenticationProvider完成的。web表单的对应的AuthenticationProvider实现类为DaoAuthenticationProvider,它的内部又维护着一个UserDetailsService负责UserDetails的获取。最终AuthenticationProvider将UserDetails填充至Authentication。
4.2.2.1 AuthenticationProvider
通过前面的Spring Security认证流程我们得知,认证管理器(AuthenticationManager)委托 AuthenticationProvider 完成认证工作。
AuthenticationProvider是一个接口 ,定义如下:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.security.authentication;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
public interface AuthenticationProvider {
Authentication authenticate(Authentication var1) throws AuthenticationException;
boolean supports(Class<?> var1);
}
authenticate()方法定义了认证的实现过程,它的参数是一个Authentication ,里面包含了登录用户所提交的用户 密码等。而返回值也是一个Authentication ,这个Authentication则是在认证成功后,将用户的权限及其他信息重新组装后生成。
Spring Security中维护着一个List
列表,存放多种认证方式,不同的认证方式使用不同的AuthenticationProvider。如使用用户名密码登录时,使用AuthenticationProviderl ,短信登录时使用 Authentication Provider2等等这样的例子很多。
每个AuthenticationProvider需要实现supports ()方法来表明自己支持的认证方式,如我们使用表单方式认证, 在提交请求时Spring Security会生成UsernamePasswordAuthenticationToken ,它是一个Authentication ,里面封装着用户提交的用户名、密码信息。
而对应哪个AuthenticationProvider来处理它?
我们在 DaoAuthenticationProvider的基类 AbstractUserDetailsAuthenticationProvider 发现以下代码:
public boolean supports(Class<?> authentication) {
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
}//149行
也就是说当web表单提交用户名密码时,Spring Security由DaoAuthenticationProvider处理。
最后,我们来看一下Authentication(认证信息)的结构,它是一个接口 ,我们之前提到的 UsernamePasswordAuthenticationToken就是它的实现之一:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.security.core;
import java.io.Serializable;
import java.security.Principal;
import java.util.Collection;
public interface Authentication extends Principal, Serializable {//1
Collection<? extends GrantedAuthority> getAuthorities();//2
Object getCredentials();//3
Object getDetails();//4
Object getPrincipal();//5
boolean isAuthenticated();
void setAuthenticated(boolean var1) throws IllegalArgumentException;
}
(1 ) Authentication是spring security包中的接口,直接继承自Principal类,而Principal是位于 java.security 包中的。它是表示着一个抽象主体身份,任何主体都有一个名称,因此包含一个getName()方法。
(2 ) getAuthorities(),权限信息列表,默认是GrantedAuthority接口的一些实现类,通常是代表权限信息的一系列字符串。
(3 ) getCredentials(),凭证信息,用户输入的密码字符串,在认证过后通常会被移除,用于保障安全。
(4 ) getDetails(),细节信息,web应用中的实现接口通常为WebAuthenticationDetails ,它记录了访问者的ip地址和sessionld的值。
(5 ) getPrincipal(),身份信息,大部分情况下返回的是UserDetails接口的实现类,UserDetails代表用户的详细信息,从Authentication中取出来的UserDetails就是当前登录用户信息,它也是框架中的常用接口之一。
附参考代码:
/*
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*/
package java.security;
import javax.security.auth.Subject;
/**
* This interface represents the abstract notion of a principal, which
* can be used to represent any entity, such as an individual, a
* corporation, and a login id.
*
* @see java.security.cert.X509Certificate
*
* @author Li Gong
*/
public interface Principal {
/**
* Compares this principal to the specified object. Returns true
* if the object passed in matches the principal represented by
* the implementation of this interface.
*
* @param another principal to compare with.
*
* @return true if the principal passed in is the same as that
* encapsulated by this principal, and false otherwise.
*/
public boolean equals(Object another);
/**
* Returns a string representation of this principal.
*
* @return a string representation of this principal.
*/
public String toString();
/**
* Returns a hashcode for this principal.
*
* @return a hashcode for this principal.
*/
public int hashCode();
/**
* Returns the name of this principal.
*
* @return the name of this principal.
*/
public String getName();
/**
* Returns true if the specified subject is implied by this principal.
*
* <p>The default implementation of this method returns true if
* {@code subject} is non-null and contains at least one principal that
* is equal to this principal.
*
* <p>Subclasses may override this with a different implementation, if
* necessary.
*
* @param subject the {@code Subject}
* @return true if {@code subject} is non-null and is
* implied by this principal, or false otherwise.
* @since 1.8
*/
public default boolean implies(Subject subject) {
if (subject == null)
return false;
return subject.getPrincipals().contains(this);
}
}
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.security.core;
import java.io.Serializable;
public interface GrantedAuthority extends Serializable {
String getAuthority();
}
原文始发于微信公众号(步尔斯特):【微服务|Spring Security⑪】spring security认证流程之AuthenticationProvider
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/47994.html