Security 、 shiro 和oauth2三方认证登录de

2019-01-08  本文已影响0人  Snail127

security 入门教程推荐(此教程写的很基础,解释也比较详细,security入门优质教程)
社区 Spring Security 从入门到进阶系列教程

项目地址:https://github.com/athc/hippo

spring security

spring boot 整合 security

org.springframework.security.core.userdetails.User
org.springframework.security.core.userdetails.UserDetails   

1 . 实现UserDetailsService的loadUserByUsername方法,作用是从数据库获取用户信息

//给自定义认证方式添加加密方式,在userDetailsService将密码交给security去验证,在认证管理中配置密码验证方式
@Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
  return new User(userInfo.getAccount(), userInfo.getPassword(), roles);
}

2 . 实现AuthenticationProvider的authenticate方法根据UserDetails实现类获取用户信息进行用户密码,状态等相关验证

3 . 告诉security认证方式

  /**
 * 添加自定义登录到认证security管理
 * 
 */
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
  //用户认证逻辑,这里可以只配置userAuthenticationProvider 剩下的逻辑判断在provider中完成,如果配置了userDetailsService会去验证密码
  auth.authenticationProvider(userAuthenticationProvider)
          //获取用户信息
     // .userDetailsService(userDetailsService) 
      //密码加密方式
      //.passwordEncoder(passwordEncoder());
}

4 . 访问资源控制,http.authorizeRequests()方法有多个子节点,每个macher按照他们的声明顺序执行,路径配置顺序有要求 ,匹配就返回.
hasAnyAuthority("USER")需要有USER权限才能访问;
hasAnyRole("ADMIN")会自动给ADMIN加上ROLE_前缀,需要有ROLE_ADMIN角色才能访问。

/**
     * security 拦截路径
     * http.authorizeRequests()方法有多个子节点,每个macher按照他们的声明顺序执行
     * 路径配置顺序有要求 ,匹配就返回
     *
     * @param http
     * @throws Exception
     */
    @Override protected void configure(HttpSecurity http) throws Exception {
      http.csrf().disable()
          .authorizeRequests()
          .antMatchers("/security/login/**").permitAll()
          .antMatchers("/security/user/**").hasAnyAuthority("USER")
          .antMatchers("/security/role/**").hasAnyRole("ADMIN")
          .anyRequest().authenticated()
          .and()
          .rememberMe()
          .key("my-secret")
          .rememberMeCookieName("my-cookie-name")
          .tokenValiditySeconds(24 * 60 * 60)
          .and()
          .formLogin()
          .and()
          .logout()
          .and()
          .httpBasic()
      ;
      // 在 UsernamePasswordAuthenticationFilter 前添加自定义过滤器 BeforeLoginFilter 
      http.addFilterBefore(new BeforeLoginFilter(), UsernamePasswordAuthenticationFilter.class);
    }

整合oauth2

项目地址:https://github.com/athc/hippo/tree/master/oauth2-security

security-oauth2区分了客户端和用户。

5 . 实现ClientDetailsService的loadClientByClientId方法,实现客户端认证

6 . 配置认证server(@EnableAuthorizationServer)通过继承AuthorizationServerConfigurerAdapter配置认证oauth2自定义客户端和用户认证

//client认证
@Override
  public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    clients.withClientDetails(clientDetailsService);
  }

  @Override
  public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
    endpoints
            //token存储位置
        .tokenStore(new InMemoryTokenStore())
        //将web security配置的authenticationManager
        .authenticationManager(authenticationManager)
        //刷新token会用到userDetailsService
        .userDetailsService(userDetailsService)
        .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
  }

  @Override
  public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
    //允许验证token 接口访问,单点登录会访问这个接口验证token是否有效
    oauthServer.checkTokenAccess("permitAll()");
    //加密方式
    oauthServer.passwordEncoder(passwordEncoder());
    //允许表单认证
    oauthServer.allowFormAuthenticationForClients();
  }

7 . 修改security的资源控制,不拦截oauth2资源

@Override protected void configure(HttpSecurity http) throws Exception {
      http
          .authorizeRequests()
          .antMatchers("/oauth/*").permitAll()
          .and().httpBasic()
      ;
    }
    
   /**
      * 在这security中,把AuthenticationManager交给Spring,
      * 这一步的配置是必不可少的,否则SpringBoot会自动配置一个AuthenticationManager,覆盖掉内存中的用户
      */
     @Bean
     @Override
     public AuthenticationManager authenticationManagerBean() throws Exception {
       AuthenticationManager manager = super.authenticationManagerBean();
       return manager;
     }

8 . 配置资源server(@EnableResourceServer) 继承ResourceServerConfigurerAdapter配置oauth2资源控制

@Configuration
@EnableResourceServer
class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

  @Override
  public void configure(ResourceServerSecurityConfigurer resources) {
    //资源id和loadClientByClientId查询到的相匹配
    resources.resourceId("API");
  }

  @Override
  public void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
        //必须认证过后才可以访问
        .antMatchers("/security/user/**").hasAnyAuthority("USER")
        .antMatchers("/security/role/**").hasAnyRole("ADMIN")
        .anyRequest().permitAll()
    ;
  }
}
/**
 * oauth2 几种获取token方式 client 可用basic 方式传递
 * refresh token: http://localhost:8013/oauth/token?grant_type=refresh_token&refresh_token=3680e51e-fbf4-417a-85d9-6a8205c14c0a&client_id=user&client_secret=123456
 * client: http://localhost:8013/oauth/token?client_id=user&client_secret=123456&scope=read&grant_type=client_credentials
 * password: http://localhost:8013/oauth/token?username=zhangsan&password=123456&grant_type=password&scope=read&client_id=user&client_secret=1234567
 * authorization code: http://localhost:8013/oauth/authorize?response_type=code&client_id=code&redirect_uri=http://localhost:8013/security/login&scope=all
 */

整合oauth2 短信认证登录

项目地址:https://github.com/athc/hippo/tree/master/oauth-third

1 拦截器拦截短信验证登录

继承认证拦截器AbstractAuthenticationProcessingFilter,重写认证方法
获取到手机号验证码,组装认证认证的Token类,提交认证
流程大致为:

1 拦截短信认证登录,提交短信认证

2 短信认证逻辑处理,认证成功,提交认证信息

3 生成 token

@Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) {
 //短信验证预处理  
 if (!RequestMethod.POST.name().equals(request.getMethod())) {
     throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
   }
   String mobile = request.getParameter("mobile").trim();
   String code = request.getParameter("code").trim();
   if (mobile.isEmpty() || code.isEmpty()) {
     throw new VerifyException("mobile or code cant be null");
   }
   
   //组装认证参数
   SmsToken authRequest = new SmsToken(mobile, code, new ArrayList<SimpleGrantedAuthority>());
   setDetails(request, authRequest);
   //提交authenticationManager 认证
  
   return this.getAuthenticationManager().authenticate(authRequest);
 }

security 配置短信认证 逻辑处理provider

@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
  //密码认证
  auth
      .authenticationProvider(userAuthenticationProvider)
      .userDetailsService(userDetailsService)
      //密码验证方式
      .passwordEncoder(new BCryptPasswordEncoder())
  ;
  //sms认证
  auth
      .authenticationProvider(smsProvider)
      .userDetailsService(userDetailsService)
  ;
}

类似 用户名密码认证的短信认证 provider

@Override public Authentication authenticate(Authentication authentication) {
 //短信验证码逻辑处理
   SmsToken token = (SmsToken) authentication;
   String mobile = (String) token.getPrincipal();
   String code = (String) token.getCredentials();
   UserDetails user = userDetailsService.loadUserByUsername(mobile);
   logger.info(code);
   //fixme: 验证code
   if (code != code) {
     throw new CredentialsExpiredException("$code expired.");
   }
   //返回认证完成Token
   return new SmsToken(user, null, user.getAuthorities());
 }

//支持自定义Token
 @Override public boolean supports(Class<?> authentication) {
   return SmsToken.class.isAssignableFrom(authentication);
 }

整合oauth2 三方认证登录

项目地址:https://github.com/athc/hippo/tree/master/oauth-third

参数注入到类

@Bean
  @ConfigurationProperties("sina.client")
  public AuthorizationCodeResourceDetails sina() {
    return new AuthorizationCodeResourceDetails();
  }

  @Bean
  @Qualifier("sinaResource")
  @Primary
  @ConfigurationProperties("sina.resource")
  public ResourceServerProperties sinaResource() {
    return new ResourceServerProperties();
  }

三方登录请求拦截

 private Filter ssoFilter() {
    CompositeFilter filter = new CompositeFilter();
    List<Filter> filters = new ArrayList<>();
    OAuth2ClientAuthenticationProcessingFilter sinaFilter = new OAuth2ClientAuthenticationProcessingFilter("/login/sina");
    OAuth2RestTemplate sinaTemplate = new OAuth2RestTemplate(sina(), oauth2ClientContext);
    sinaFilter.setRestTemplate(sinaTemplate);
    //自定义userInfo 获取
    SinaUserInfoTokenServices sinaTokenServices = new SinaUserInfoTokenServices(sinaResource().getUserInfoUri(), sina().getClientId());
    sinaTokenServices.setRestTemplate(sinaTemplate);
    sinaFilter.setTokenServices(sinaTokenServices);
    //认证成功处理
    sinaFilter.setAuthenticationSuccessHandler(authSuccessHandler);
    //获取到三方信息 自定义处理 存库等
    sinaTokenServices.setAuthoritiesExtractor(new MyAuthoritiesExtractor());
    //三方登录权限处理
    sinaTokenServices.setPrincipalExtractor(new MyPrincipalExtractor());
    filters.add(sinaFilter);
    filter.setFilters(filters);
    return filter;
  }

将拦截器放到拦截链中

自定义token:

实现自定义token产生
public class UserTokenEnhancer implements TokenEnhancer {
  @Override public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
    DefaultOAuth2AccessToken result = (DefaultOAuth2AccessToken) accessToken;
    //uuid 去掉   `-`
    result.setValue(result.getValue().replace("-", ""));
    result.setRefreshToken(new DefaultOAuth2RefreshToken(UUID.randomUUID().toString().replace("-", "")));
    //todo: 这里可以自定义token数据结构
    return result;
  }
}

从获取的三方信息中 获取有用的信息

MyPrincipalExtractor implements PrincipalExtractor

三方认证登录获取的权限

MyAuthoritiesExtractor implements AuthoritiesExtractor

security+oauth2+sso demo地址:https://github.com/athc/ath-cloud -----用的kotlin写的单点登录demo

参考链接:
https://spring.io/guides/tutorials/spring-boot-oauth2/

上一篇下一篇

猜你喜欢

热点阅读