AuthenticationProvider接口

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值