Authentication authenticate(Authentication authentication) throws AuthenticationException;
boolean supports(Class<?> authentication);
AnonymousAuthenticationProvider实现类
// 匿名认证
// AnonymousAuthenticationToken中的权限不能为null
public class AnonymousAuthenticationProvider {
// AnonymousAuthenticationToken.getKeyHash() 必须等于该key
// 该key必不为null
private String key;
// Authentication的实现类必须是AnonymousAuthenticationToken,才执行认证
@Override
public boolean supports(Class<?> authentication) {
return (AnonymousAuthenticationToken.class.isAssignableFrom(authentication));
}
@Override
public Authentication authenticate(Authentication authentication) throws
AuthenticationException {
if (!supports(authentication.getClass())) {
return null;
}
// 判断key与AnonymousAuthenticationToken中key的hashCode()
if (this.key.hashCode() != ((AnonymousAuthenticationToken)
authentication).getKeyHash()) {
throw new BadCredentialsException("));
}
return authentication;
}
}
DaoAuthenticationProvider实现类
// 使用UserDetailsService组件认证
public class DaoAuthenticationProvider{
// 无参构造时,初始化passwordEncoder = DelegatingPasswordEncoder对象
private PasswordEncoder passwordEncoder;
// 使用 loadUserByUsername(String username)查找username的用户信息
// 自定义实现查找逻辑
private UserDetailsService userDetailsService;
// 更新密码,返回最新的密码 updatePassword(UserDetails user, String newPassword)
private UserDetailsPasswordService userDetailsPasswordService;
// 用户缓存。默认不存放UserDetails对象。
private UserCache userCache = new NullUserCache();
// 默认对权限不处理。例如SimpleAuthorityMapper作用加默认权限及加ROLE_
private GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper();
// 将PrincipalAsString
private boolean forcePrincipalAsString = false;
// 检查用户的accountNonLocked,enabled,accountNonExpired
// 某个字段为false会抛出异常
private UserDetailsChecker preAuthenticationChecks = new DefaultPreAuthenticationChecks();
// 密码验证后,检查用户的credentialsNonExpired是否过期
private UserDetailsChecker postAuthenticationChecks = new DefaultPostAuthenticationChecks();
// authentication为UsernamePasswordAuthenticationToken类或子类
@Override
public boolean supports(Class<?> authentication) {
return
(UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
}
// 核心方法。认证逻辑
public Authentication authenticate(Authentication authentication){
// 1.从authentication对象中拿到username
String username = determineUsername(authentication);
// 2.从userCache中根据username拿用户详情
boolean cacheWasUsed = true;
UserDetails user = this.userCache.getUserFromCache(username);
// 3.user为null时,cacheWasUsed = false
if (user == null) {
cacheWasUsed = false;
4.使用userDetailsService.loadUserByUsername(username)查询用户详情
user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
}
// 5.user不为null时,使用preAuthenticationChecks对象检查
this.preAuthenticationChecks.check(user);
// 6.用户credentials为null时,抛出异常
// 使用passwordEncoder进行密码验证
additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);
// 7.使用postAuthenticationChecks对象检查
this.postAuthenticationChecks.check(user);
// 8.如果用户从数据库取出,就执行if里面语句。从缓存中取出,就不用放入缓存
if (!cacheWasUsed) {
this.userCache.putUserInCache(user);
}
// 9.取出username作为返回值
Object principalToReturn = user;
if (this.forcePrincipalAsString) {
principalToReturn = user.getUsername();
}
// 10. a.userDetailsPasswordService 不为null且passwordEncoder.upgradeEncoding
// 为ture,则updatePassword()
// b.authoritiesMapper组件映射权限,设置result.setDetails
// c.设置已认证
return createSuccessAuthentication(principalToReturn, authentication, user);
}
}
RememberMeAuthenticationProvider实现类
public class RememberMeAuthenticationProvider {
private String key;
// authentication为RememberMeAuthenticationToken类或子类,则支持认证
@Override
public boolean supports(Class<?> authentication) {
return (RememberMeAuthenticationToken.class.isAssignableFrom(authentication));
}
public Authentication authenticate(Authentication authentication) throws
AuthenticationException {
if (!supports(authentication.getClass())) {
return null;
}
if (this.key.hashCode() != ((RememberMeAuthenticationToken)
authentication).getKeyHash()) {
throw new BadCredentialsException(...);
}
return authentication;
}
}
JaasAuthenticationProvider实现类
public class JaasAuthenticationProvider {
// 登陆配置。例如new ClassPathResource("login.conf")
// 实现LoginModule接口
// initialize()
private Resource loginConfig;
// 登陆上下文的名称
private String loginContextName = "SPRINGSECURITY";
private boolean refreshConfigurationOnStartup = true;
// 根据用户principal,获取权限(角色)
private AuthorityGranter[] authorityGranters;
// 支持UsernamePasswordAuthenticationToken认证
@Override
public boolean supports(Class<?> aClass) {
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(aClass);
}
@Override
public Authentication authenticate(Authentication auth){
if (!(auth instanceof UsernamePasswordAuthenticationToken)) {
return null;
}
UsernamePasswordAuthenticationToken request =
(UsernamePasswordAuthenticationToken) auth;
Set<GrantedAuthority> authorities;
// 1.创建登陆上下文对象,通过 new LoginContext对象。用loginContextName获取ConfigFile
// 中的AppConfigurationEntry对象,初始化moduleStack属性
// 初始化其属性callbackHandler
// (LoginContext.SecureCallbackHandler,其属性ch=InternalCallbackHandler(auth))
LoginContext loginContext = createLoginContext(new
InternalCallbackHandler(auth));
loginContext.login()->{
loginSucceeded = false;
// 2.主体为null时。创建主体
// 初始化principals,pubCredentials,privCredentials
if (subject == null) {
subject = new Subject();
}
try {
// module invoked in doPrivileged
// 执行登陆方法
// 3.调用LoginContext.moduleStack对象的initialize方法(实现LoginModule接口)
//
// 4.调用LoginContext.moduleStack对象的login方法(实现LoginModule接口)
// 例如最后的TestLoginModule
invokePriv(LOGIN_METHOD);
// 5.调用LoginContext.moduleStack对象的login方法(实现LoginModule接口)
// 初始化主体的loginSuceeded=true及principals属性
invokePriv(COMMIT_METHOD);
loginSucceeded = true;
} catch (LoginException le) {
// 6.调用LoginContext.moduleStack对象的abort方法(实现LoginModule接口)
// 执行丢弃方法
invokePriv(ABORT_METHOD);
}
};
// 6. 获取主体中的principals
Set<Principal> principals = loginContext.getSubject().getPrincipals();
// 7. 根据principal获取权限,其权限类为JaasGrantedAuthority
// 例如用户拥有两个principal1,principal2。其中principal1的角色为role1,role2。
// 则new JaasGrantedAuthority("role1", "principal1")
// new JaasGrantedAuthority("role2", "principal2")
authorities = getAuthorities(principals);
// 8.new JaasAuthenticationToken(用户名,验证密码,权限数组,loginContext)
// authenticated=true
JaasAuthenticationToken result = new
JaasAuthenticationToken(request.getPrincipal(),
request.getCredentials(), new ArrayList<>(authorities),
loginContext);
// Publish the success event
// this.applicationEventPublisher.publishEvent(new
JaasAuthenticationSuccessEvent(token));
//
publishSuccessEvent(result);
// we're done, return the token.
return result;
};
}
public void afterPropertiesSet() throws Exception {
Assert.hasLength(getLoginContextName(), () -> "loginContextName must be set on " + getClass());
Assert.notNull(this.loginConfig, () -> "loginConfig must be set on " + getClass());
//
configureJaas(this.loginConfig)->{
// 如果Security属性中有login.config.url1不为null,则设置其资源
// 如果Security属性中有login.config.url1、login.config.url2都不为null,
// 则使用login.config.url2设置其资源
configureJaasUsingLoop()->{
// 获取loginConf资源的路径
String loginConfigUrl = convertLoginConfigToUrl();
int n = 1;
final String prefix = "login.config.url.";
boolean alreadySet = false;
String existing;
// Security.getProperty("login.config.url1")属性不为null时
while ((existing = Security.getProperty(prefix + n)) != null) {
alreadySet = existing.equals(loginConfigUrl);
if (alreadySet) {
break;
}
n++;
}
// Security.getProperty("login.config.url1")属性为null时
// 设置Security.setProperty("login.config.url1",loginConfigUrl)
if (!alreadySet) {
String key = prefix + n;
log.debug(LogMessage.format("Setting security property [%s] to: %s",
key, loginConfigUrl));
Security.setProperty(key, loginConfigUrl);
}
}
// 调用ConfigFile.refresh()。
// 1.SecurityManager sm 不为null,sm.checkPermission(
// new AuthPermission("refreshLoginConfiguration"))
// 2.AccessController.doPrivileged()。调用configFile.init()。用初始化
// Map<String, List<AppConfigurationEntry>> configuration;
Configuration.getConfiguration().refresh();
};
Assert.notNull(Configuration.getConfiguration(),
""+ "Configuration.getConfiguration().");
}
}
public class TestLoginModule implements LoginModule {
private String password;
private String user;
private Subject subject;
// 将主体赋值到登陆模块,同时将要登陆验证的用户名和密码赋值到登陆模块
public void initialize(Subject subject, CallbackHandler callbackHandler, Map
sharedState, Map options) {
this.subject = subject;
try {
TextInputCallback textCallback = new TextInputCallback("prompt")
NameCallback nameCallback = new NameCallback("prompt");
PasswordCallback passwordCallback = new PasswordCallback("prompt", false);
// 使用InternalCallbackHandler处理
// JaasAuthenticationProviderthis.callbackHandlers(配置的所有回调)
// 例如JaasNameCallbackHandler:如果Callback为NameCallback,则从auth取出名称
// 设置到callBack对象中
// 例如配置JaasPasswordCallbackHandler:如果Callback为PasswordCallback,则从
// auth取出密码,设置到callback中
callbackHandler.handle(new Callback[] { textCallback, nameCallback,
passwordCallback });
this.password = new String(passwordCallback.getPassword());
this.user = nameCallback.getName();
}
catch (Exception ex) {
throw new RuntimeException(ex);
}
}
// 登陆用户与数据库用户user[password]进行认证
// 添加principal(TEST_PRINCIPAL,NULL_PRINCIPAL)
@Override
public boolean login() throws LoginException {
if (!this.user.equals("user")) {
throw new LoginException("Bad User");
}
if (!this.password.equals("password")) {
throw new LoginException("Bad Password");
}
this.subject.getPrincipals().add(() -> "TEST_PRINCIPAL");
this.subject.getPrincipals().add(() -> "NULL_PRINCIPAL");
return true;
}
}
OAuth2AuthorizationCodeAuthenticationProvider实现类
// OAuth2AuthorizationCodeAuthenticationToken
public class OAuth2AuthorizationCodeAuthenticationProvider {
private static final String INVALID_STATE_PARAMETER_ERROR_CODE = "invalid_state_parameter";
private final OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> accessTokenResponseClient;
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
OAuth2AuthorizationCodeAuthenticationToken authorizationCodeAuthentication = (OAuth2AuthorizationCodeAuthenticationToken)authentication;
OAuth2AuthorizationResponse authorizationResponse = authorizationCodeAuthentication.getAuthorizationExchange().getAuthorizationResponse();
// authorizationResponse状态为error,报异常
if (authorizationResponse.statusError()) {
throw new OAuth2AuthorizationException(authorizationResponse.getError());
} else {
OAuth2AuthorizationRequest authorizationRequest = authorizationCodeAuthentication.getAuthorizationExchange().getAuthorizationRequest();
// 认证请求和认证相应的state不一样,报异常
if (!authorizationResponse.getState().equals(authorizationRequest.getState())) {
OAuth2Error oauth2Error = new OAuth2Error("invalid_state_parameter");
throw new OAuth2AuthorizationException(oauth2Error);
} else {
// 获取accessToken响应
OAuth2AccessTokenResponse accessTokenResponse = this.accessTokenResponseClient.getTokenResponse(new OAuth2AuthorizationCodeGrantRequest(authorizationCodeAuthentication.getClientRegistration(), authorizationCodeAuthentication.getAuthorizationExchange()));
// 生成OAuth2AuthorizationCodeAuthenticationToken
OAuth2AuthorizationCodeAuthenticationToken authenticationResult = new OAuth2AuthorizationCodeAuthenticationToken(authorizationCodeAuthentication.getClientRegistration(), authorizationCodeAuthentication.getAuthorizationExchange(), accessTokenResponse.getAccessToken(), accessTokenResponse.getRefreshToken(), accessTokenResponse.getAdditionalParameters());
// 设置details authenticationResult.setDetails(authorizationCodeAuthentication.getDetails());
return authenticationResult;
}
}
}
}
OAuth2LoginAuthenticationProvider实现类
// OAuth2LoginAuthenticationToken
public class OAuth2LoginAuthenticationProvider {
private final OAuth2AuthorizationCodeAuthenticationProvider authorizationCodeAuthenticationProvider;
private final OAuth2UserService<OAuth2UserRequest, OAuth2User> userService;
private GrantedAuthoritiesMapper authoritiesMapper = (authorities) -> {
return authorities;
};
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
OAuth2LoginAuthenticationToken loginAuthenticationToken = (OAuth2LoginAuthenticationToken)authentication;
// 认证请求scope="openid"时,返回null
if (loginAuthenticationToken.getAuthorizationExchange().getAuthorizationRequest().getScopes().contains("openid")) {
return null;
} else {
OAuth2AuthorizationCodeAuthenticationToken authorizationCodeAuthenticationToken;
try {
authorizationCodeAuthenticationToken = (OAuth2AuthorizationCodeAuthenticationToken)this.authorizationCodeAuthenticationProvider.authenticate(new OAuth2AuthorizationCodeAuthenticationToken(loginAuthenticationToken.getClientRegistration(), loginAuthenticationToken.getAuthorizationExchange()));
} catch (OAuth2AuthorizationException var9) {
OAuth2Error oauth2Error = var9.getError();
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString(), var9);
}
OAuth2AccessToken accessToken = authorizationCodeAuthenticationToken.getAccessToken();
Map<String, Object> additionalParameters = authorizationCodeAuthenticationToken.getAdditionalParameters();
OAuth2User oauth2User = this.userService.loadUser(new OAuth2UserRequest(loginAuthenticationToken.getClientRegistration(), accessToken, additionalParameters));
Collection<? extends GrantedAuthority> mappedAuthorities = this.authoritiesMapper.mapAuthorities(oauth2User.getAuthorities());
OAuth2LoginAuthenticationToken authenticationResult = new OAuth2LoginAuthenticationToken(loginAuthenticationToken.getClientRegistration(), loginAuthenticationToken.getAuthorizationExchange(), oauth2User, mappedAuthorities, accessToken, authorizationCodeAuthenticationToken.getRefreshToken());
authenticationResult.setDetails(loginAuthenticationToken.getDetails());
return authenticationResult;
}
}
}