资讯专栏INFORMATION COLUMN

oauth 实现手机号码登录

hyuan / 3104人阅读

摘要:现在有一个需求就是改造实现手机号码可以登录需要重几个类第一个类手机验证码登陆第二个类验证码验证,调用公共服务查询为的,并判断其与验证码是否匹配第三个类第四个类第五个类不存在不匹配最后在配置一下设置禁止隐藏用户未找到异常使用进行密码

现在有一个需求就是改造 oauth2.0 实现手机号码可以登录 需要重几个类

第一个类

public class PhoneLoginAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

private static final String SPRING_SECURITY_RESTFUL_PHONE_KEY = "phone";
private static final String SPRING_SECURITY_RESTFUL_VERIFY_CODE_KEY = "verifyCode";

private static final String SPRING_SECURITY_RESTFUL_LOGIN_URL = "/oauth/phoneLogin";
private boolean postOnly = true;

public PhoneLoginAuthenticationFilter() {
    super(new AntPathRequestMatcher(SPRING_SECURITY_RESTFUL_LOGIN_URL, "POST"));
}


@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
    if (postOnly && !request.getMethod().equals("POST")) {
        throw new AuthenticationServiceException(
                "Authentication method not supported: " + request.getMethod());
    }

    AbstractAuthenticationToken authRequest;
    String principal;
    String credentials;

    // 手机验证码登陆
    principal = obtainParameter(request, SPRING_SECURITY_RESTFUL_PHONE_KEY);
    credentials = obtainParameter(request, SPRING_SECURITY_RESTFUL_VERIFY_CODE_KEY);

    principal = principal.trim();
    authRequest = new PhoneAuthenticationToken(principal, credentials);

    // Allow subclasses to set the "details" property
    setDetails(request, authRequest);
    return this.getAuthenticationManager().authenticate(authRequest);
}

private void setDetails(HttpServletRequest request,
                        AbstractAuthenticationToken authRequest) {
    authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
}

private String obtainParameter(HttpServletRequest request, String parameter) {
    String result =  request.getParameter(parameter);
    return result == null ? "" : result;
}

第二个类

public class PhoneAuthenticationProvider extends MyAbstractUserDetailsAuthenticationProvider {

private UserDetailsService userDetailsService;

@Override
protected void additionalAuthenticationChecks(UserDetails var1, Authentication authentication) throws AuthenticationException {

    if(authentication.getCredentials() == null) {
        this.logger.debug("Authentication failed: no credentials provided");
        throw new BadCredentialsException(this.messages.getMessage("PhoneAuthenticationProvider.badCredentials", "Bad credentials"));
    } else {
        String presentedPassword = authentication.getCredentials().toString();

        // 验证码验证,调用公共服务查询 key 为authentication.getPrincipal()的value, 并判断其与验证码是否匹配
        if(!"1000".equals(presentedPassword)){
            this.logger.debug("Authentication failed: verifyCode does not match stored value");
            throw new BadCredentialsException(this.messages.getMessage("PhoneAuthenticationProvider.badCredentials", "Bad verifyCode"));
        }
    }
}

@Override
protected Authentication createSuccessAuthentication(Object principal, Authentication authentication, UserDetails user) {
    PhoneAuthenticationToken result = new PhoneAuthenticationToken(principal, authentication.getCredentials(), user.getAuthorities());
    result.setDetails(authentication.getDetails());
    return result;
}

@Override
protected UserDetails retrieveUser(String phone, Authentication authentication) throws AuthenticationException {
    UserDetails loadedUser;
    try {
        loadedUser = this.getUserDetailsService().loadUserByUsername(phone);
    } catch (UsernameNotFoundException var6) {
        throw var6;
    } catch (Exception var7) {
        throw new InternalAuthenticationServiceException(var7.getMessage(), var7);
    }

    if(loadedUser == null) {
        throw new InternalAuthenticationServiceException("UserDetailsService returned null, which is an interface contract violation");
    } else {
        return loadedUser;
    }
}

@Override
public boolean supports(Class authentication) {
    return PhoneAuthenticationToken.class.isAssignableFrom(authentication);
}


public UserDetailsService getUserDetailsService() {
    return userDetailsService;
}

public void setUserDetailsService(UserDetailsService userDetailsService) {
    this.userDetailsService = userDetailsService;
}

}
第三个类

@Service
public class PhoneUserDetailService implements UserDetailsService {

private Logger logger = LoggerFactory.getLogger(this.getClass());

@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {

    System.out.println("PhoneUserDetailService");
    return new User("admin", "1000", AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER"));
}

}
第四个类

public class PhoneAuthenticationToken extends MyAuthenticationToken {

public PhoneAuthenticationToken(Object principal, Object credentials) {
    super(principal, credentials);
}

public PhoneAuthenticationToken(Object principal, Object credentials, Collection authorities) {
    super(principal, credentials, authorities);
}

}
第五个类

@Component("MyLoginAuthSuccessHandler")
public class MyLoginAuthSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {

@Autowired
private ClientDetailsService clientDetailsService;

@Autowired
private AuthorizationServerTokenServices authorizationServerTokenServices;

@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {

// String clientId = obtainParameter(request, "client_id");
// String client_secret = obtainParameter(request, "client_secret");

    String header = request.getHeader("Authorization");
    header.toLowerCase().startsWith("basic ");
    String[] strings = extractAndDecodeHeader(header, request);
    String clientId = strings[0];
    String client_secret = strings[1];
    String clientSecret = new BCryptPasswordEncoder().encode(client_secret);
    System.out.println(clientSecret);
    ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId);
    if (null == clientDetails) {
        throw new UnapprovedClientAuthenticationException("clientId不存在" + clientId);
    } else if (!new BCryptPasswordEncoder().matches(client_secret, clientDetails.getClientSecret())) {
        throw new UnapprovedClientAuthenticationException("clientSecret不匹配" + clientId);
    }

    TokenRequest tokenRequest = new TokenRequest(MapUtils.EMPTY_MAP, clientId, clientDetails.getScope(), "phone");

    OAuth2Request oAuth2Request = tokenRequest.createOAuth2Request(clientDetails);

    OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(oAuth2Request, authentication);

    OAuth2AccessToken token = authorizationServerTokenServices.createAccessToken(oAuth2Authentication);
    Set scope = token.getScope();

    StringBuffer stringBuffer = new StringBuffer();
    stringBuffer.append(scope.stream().findFirst());
    scope.stream().forEach(s -> {
        stringBuffer.append("," + s);
    });
    Map map = new HashMap<>();
    map.put("access_token", token.getValue());
    map.put("token_type", token.getTokenType());
    map.put("refresh_token", token.getRefreshToken().getValue());
    map.put("expires_in", token.getExpiresIn());
    map.put("scope", scope.stream().findFirst());
    response.setContentType("application/json;charset=UTF-8");
    response.getWriter().write(JsonUtil.toJsonString(map));
}

private String obtainParameter(HttpServletRequest request, String parameter) {
    String result = request.getParameter(parameter);
    return result == null ? "" : result;
}

private String[] extractAndDecodeHeader(String header, HttpServletRequest request)
        throws IOException {

    byte[] base64Token = header.substring(6).getBytes("UTF-8");
    byte[] decoded;
    try {
        decoded = Base64.getDecoder().decode(base64Token);
    }
    catch (IllegalArgumentException e) {
        throw new BadCredentialsException(
                "Failed to decode basic authentication token");
    }

    String token = new String(decoded,  "UTF-8");

    int delim = token.indexOf(":");

    if (delim == -1) {
        throw new BadCredentialsException("Invalid basic authentication token");
    }
    return new String[] { token.substring(0, delim), token.substring(delim + 1) };
}

}
最后在 SecurityConfig 配置一下

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private SsoUserDetailsService ssoUserDetailsService;

@Autowired
private PhoneUserDetailService phoneUserDetailService;

@Autowired
private QrUserDetailService qrUserDetailService;

@Autowired
private MyLoginAuthSuccessHandler myLoginAuthSuccessHandler;


@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

@Override
public void configure(WebSecurity web) {

    web.ignoring().antMatchers("/authentication/require", "/**/*.js",
            "/**/*.css",
            "/**/*.jpg",
            "/**/*.png",
            "/**/*.woff2",
            "/oauth/exit",
            "/oauth/logout"
    );
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .addFilterBefore(getPhoneLoginAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
            .addFilterBefore(getQrLoginAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
            .formLogin().loginPage("/authentication/require")
            .loginProcessingUrl("/authentication/form")
            .successHandler(myLoginAuthSuccessHandler).and()
            .authorizeRequests().antMatchers("/authentication/require",
            "/authentication/form",
            "/**/*.js",
            "/**/*.css",
            "/**/*.jpg",
            "/**/*.png",
            "/**/*.woff2",
            "/auth/*",
            "/oauth/*",

    )
            .permitAll()
            .anyRequest().authenticated().and().anonymous().disable().exceptionHandling().authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login?error")).and()
            .csrf().disable();
    http.addFilterBefore(myFilterSecurityInterceptor, FilterSecurityInterceptor.class);
}

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {

    auth.authenticationProvider(phoneAuthenticationProvider());
    auth.authenticationProvider(daoAuthenticationProvider());

}


@Bean
public DaoAuthenticationProvider daoAuthenticationProvider(){
    DaoAuthenticationProvider provider1 = new DaoAuthenticationProvider();
    // 设置userDetailsService
    provider1.setUserDetailsService(ssoUserDetailsService);
    // 禁止隐藏用户未找到异常
    provider1.setHideUserNotFoundExceptions(false);
    // 使用BCrypt进行密码的hash
    provider1.setPasswordEncoder(passwordEncode());
    return provider1;
}


@Bean
public PhoneAuthenticationProvider phoneAuthenticationProvider(){
    PhoneAuthenticationProvider provider = new PhoneAuthenticationProvider();
    // 设置userDetailsService
    provider.setUserDetailsService(phoneUserDetailService);
    // 禁止隐藏用户未找到异常
    provider.setHideUserNotFoundExceptions(false);
    return provider;
}


@Override
@Bean
public AuthenticationManager authenticationManager() throws Exception {
    return super.authenticationManager();
}

/**
 * 手机验证码登陆过滤器
 * @return
 */
@Bean
public PhoneLoginAuthenticationFilter getPhoneLoginAuthenticationFilter() {
    PhoneLoginAuthenticationFilter filter = new PhoneLoginAuthenticationFilter();
    try {
        filter.setAuthenticationManager(this.authenticationManagerBean());
    } catch (Exception e) {
        e.printStackTrace();
    }
    filter.setAuthenticationSuccessHandler(myLoginAuthSuccessHandler);
    filter.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler("/login?error"));
    return filter;
}

}
配置好了

本文代码参考 https://github.com/fp2952/spr... 来实现 本人已经验证

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/73061.html

相关文章

  • Spring Security Oauth2.0 实现短信验证码登录

    摘要:验证码的发放校验逻辑比较简单,方法后通过全局判断请求中是否和手机号匹配集合,重点逻辑是令牌的参数 spring security oauth2 登录过程详解 ​ showImg(https://segmentfault.com/img/remote/1460000012811024); ​ 定义手机号登录令牌 /** * @author lengleng * @date 2018/...

    陆斌 评论0 收藏0
  • Spring Security OAuth2 优雅的集成短信验证码登录以及第三方登录

    摘要:前言基于做微服务架构分布式系统时,作为认证的业内标准,也提供了全套的解决方案来支持在环境下使用,提供了开箱即用的组件。 前言 基于SpringCloud做微服务架构分布式系统时,OAuth2.0作为认证的业内标准,Spring Security OAuth2也提供了全套的解决方案来支持在Spring Cloud/Spring Boot环境下使用OAuth2.0,提供了开箱即用的组件。但...

    yck 评论0 收藏0
  • 前后端分离项目 — 基于SpringSecurity OAuth2.0用户认证

    摘要:前言现在的好多项目都是基于移动端以及前后端分离的项目,之前基于的前后端放到一起的项目已经慢慢失宠并淡出我们视线,尤其是当基于的微服务架构以及单页面应用流行起来后,情况更甚。使用生成是什么请自行百度。 1、前言 现在的好多项目都是基于APP移动端以及前后端分离的项目,之前基于Session的前后端放到一起的项目已经慢慢失宠并淡出我们视线,尤其是当基于SpringCloud的微服务架构以及...

    QLQ 评论0 收藏0
  • 聊聊二维码登录

    摘要:场景主要的场景有如下几个扫二维码登录版系统比如微信版,在手机端微信登录的前提下,扫二维码确认,自动登录网页版。小结二维码扫描登录是个挺潮流的功能,这要求既有系统增加改造,也要求针对这种形式的登录带来潜在的攻击进行安全防范。 序 本文主要来研究一下二维码登录的相关场景和原理。 场景 主要的场景有如下几个: app扫二维码登录pc版系统 比如微信web版,在手机端微信登录的前提下,扫二维码...

    Tikitoo 评论0 收藏0
  • 说一说几种登录认证方式,你用的哪一种

    摘要:登录认证几乎是任何一个系统的标配,系统客户端等,好多都需要注册登录授权认证。假设我们开发了一个电商平台,并集成了微信登录,以这个场景为例,说一下的工作原理。微信网页授权是授权码模式的授权模式。 登录认证几乎是任何一个系统的标配,web 系统、APP、PC 客户端等,好多都需要注册、登录、授权认证。 场景说明 以一个电商系统,假设淘宝为例,如果我们想要下单,首先需要注册一个账号。拥有了账...

    idealcn 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<