03.自定义认证方式

  1. 定义Granter
/**
 * @ClassName MobileAuthenticationProvider
 * @Description TODO
 * @Author CY
 * @Date 2023/11/21 10:12
 * @Version 1.0
 */
public class EmailPwdGranter extends AbstractTokenGranter {
    private static final String GRANT_TYPE = "email_password";
    private final AuthenticationManager authenticationManager;

    public EmailPwdGranter(AuthenticationManager authenticationManager, AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory) {
        super(tokenServices, clientDetailsService, requestFactory, GRANT_TYPE);
        this.authenticationManager = authenticationManager;
    }

    @Override
    protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
        Map<String, String> parameters = new LinkedHashMap<>(tokenRequest.getRequestParameters());
        String mobile = parameters.get("email");
        String password = parameters.get("password");
        parameters.remove("password");
        Authentication userAuth = new EmailAuthenticationToken(mobile, password);
        ((AbstractAuthenticationToken) userAuth).setDetails(parameters);

        try {
            userAuth = authenticationManager.authenticate(userAuth);
        } catch (AccountStatusException var8) {
            throw new InvalidGrantException(var8.getMessage());
        } catch (BadCredentialsException var9) {
            throw new InvalidGrantException(var9.getMessage());
        }


        if (userAuth == null || !userAuth.isAuthenticated()) {
            throw new InvalidGrantException("Could not authenticate mobile: " + mobile);
        }
        OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest);
        return new OAuth2Authentication(storedOAuth2Request, userAuth);
    }
}

cybb:Granter会将对应的Token传递给ProviderManager,进行认证

  1. 定义Token(基本是固定的,只需要添加一个构造方法,可以把该构造方法的参数名替换成自己的名字)
public class EmailAuthenticationToken extends AbstractAuthenticationToken {
    private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
    private final Object principal;
    private Object credentials;

	//可以添加一个构造方法,将参数名替换为相应的名字
    public EmailAuthenticationToken(String email, String password) {
        super(null);
        this.principal = email;
        this.credentials = password;
        setAuthenticated(false);
    }

    public EmailAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
        super(authorities);
        this.principal = principal;
        this.credentials = credentials;
        super.setAuthenticated(true);
    }

    @Override
    public Object getCredentials() {
        return this.credentials;
    }

    @Override
    public Object getPrincipal() {
        return this.principal;
    }

    @Override
    public void setAuthenticated(boolean isAuthenticated) {
        if (isAuthenticated) {
            throw new IllegalArgumentException("Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
        }
        super.setAuthenticated(false);
    }

    @Override
    public void eraseCredentials() {
        super.eraseCredentials();
    }
}
  1. 定义处理token的Provider
@Data
@Component("EmailAuthenticationProvider")
public class EmailAuthenticationProvider implements AuthenticationProvider {
    @Autowired
    private EmailUserDetailsService userDetailsService;
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public Authentication authenticate(Authentication authentication) {
        EmailAuthenticationToken authenticationToken = (EmailAuthenticationToken) authentication;
        String mobile = (String) authenticationToken.getPrincipal();
        String password = (String) authenticationToken.getCredentials();
        UserDetails user = userDetailsService.loadUserByEmail(mobile);
        if (user == null) {
            throw new BusinessException(Code.LOGIN_ERR,"邮箱号或密码错误");
        }
        if (!passwordEncoder.matches(password, user.getPassword())) {
            throw new BusinessException(Code.LOGIN_ERR,"邮箱号或密码错误");
        }
        EmailAuthenticationToken authenticationResult = new EmailAuthenticationToken(user, password, user.getAuthorities());
        authenticationResult.setDetails(authenticationToken.getDetails());
        return authenticationResult;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return EmailAuthenticationToken.class.isAssignableFrom(authentication);
    }


}

在provider处对上面定义的token进行校验(如果返回了就是验证成功了),在provider处的自由度很高,可以自定义与数据库的交互,但一般是定义一个EmailUserDetailsService来进行数据库的读取

  1. 将该provider添加到ProviderManager中!!! 在WebSecurityConfig中
   @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //这一步是配置默认的UsernamePassword中的UserDetailsService
        auth.userDetailsService(userDetailsService);

        //添加自定义的Provider到ProviderManager的provider列表中
				auth.authenticationProvider(emailAuthenticationProvider);
    }

image-20220118060824066

  1. 将Granter添加到授权模式中,在AuthorizationServer中
 @Override // 令牌端点的安全约束配置
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenServices(tokenService())//令牌管理服务
                .authenticationManager(authenticationManager)//认证管理器
                .allowedTokenEndpointRequestMethods(HttpMethod.POST)
                .accessTokenConverter(accessTokenConverter)
                .tokenStore(tokenStore)
                .setClientDetailsService(clientDetails());//客户端信息服务
        //获取原有默认的授权者(那四种模式)
        ArrayList<TokenGranter> tokenGranters = new ArrayList<>(Arrays.asList(endpoints.getTokenGranter()));
        //添加扩展的验证码模式授权者
        tokenGranters.add(new CaptchaTokenGranter(endpoints.getTokenServices(),endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory(), authenticationManager,checkCodeClient));
        //添加扩展的邮箱密码模式授权者
        tokenGranters.add(new EmailPwdGranter(authenticationManager,endpoints.getTokenServices(),endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory()));
        //添加扩展的短信验证码模式授权者
        tokenGranters.add(new SmsCodeTokenGranter(endpoints.getTokenServices(),endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory(), authenticationManager));
        CompositeTokenGranter compositeTokenGranter=new CompositeTokenGranter(tokenGranters);



               endpoints.tokenGranter(compositeTokenGranter);        //配置授权者
    }

teTokenGranter compositeTokenGranter=new CompositeTokenGranter(tokenGranters);

           endpoints.tokenGranter(compositeTokenGranter);        //配置授权者
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值