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

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/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容