Spring

Spring Security oAuth2的理解

2020-03-24  本文已影响0人  乙腾

名词解释

oAuth

定义:是一个协议。

目的:为用户资源的授权提供了一个安全的,开放,简单的标准。| 为用户授权提供安全标准。

优点:与其他授权方式不同,该标准授权不会让第三方接触到用户的账号信息。 | 该标准根本就不存用户信息。

Spring Security

定义:这是个spring提供的安全框架。

Spring Security oAuth2

定义:Spring基于oAuth2协议的安全框架。

对象:授权服务(客户端)和受保护的资源服务。

对象特点:这两者不是必须分开的,两者好多情况是属于一个模块中,可以选择按照对象为维度将服务进行拆分,注意这历史选择而不是必须。

Spring Security oAuth2的个人理解

预设网址

spring asecurity oauth2这套框架会预留两个网址:

1.AuthorizationEndpoint(授权端点)

/oauth/authorize 用来给用户授权

image

验证成功后询问是否为用户授权

image

2.TokenEndpoint

用来给服务提供token

预设网址:/oauth/token

image

实现

对于所有spring security OAuth2提供的功能适配器,可以用@Configuration配置类实现。对于授权和认证的服务配置我这里都以配置类来实现。

AuthorizationServerConfigurerAdapter/授权服务配置

这个实际类似于对应 /oauth/authorize token的配置


@Configuration //配置类

@EnableAuthorizationServer  //用于开启授权服务,

public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

}

授权功能点

1.ClientDetailsServiceConfigurer

定义客户端详细信息服务的配置程序。可以初始化客户端详细信息。
属性
clientId:(必填)客户端ID。
secret:(对于受信任的客户端是必需的)客户端密钥(如果有)。
scope:客户端的范围受到限制。如果范围未定义或为空(默认值),则客户端不受范围的限制。
authorizedGrantTypes:授权客户使用的授权类型。默认值为空。
authorities:授予客户端的权限(常规的Spring Security权限)。

@Autowired
private BCryptPasswordEncoder passwordEncoder; 注意这里是autowired 这个bean在web安全配置里配的。
/** * 配置客户端,定义客户端 * @param clients * @throws Exception */ @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients // 使用内存设置 先定义客户端的模式,可以选择内存模式,数据库模式 .inMemory() // client_id .withClient("client") // client_secret .secret(passwordEncoder.encode("secret")) // 授权类型,密码模式和刷新令牌 .authorizedGrantTypes("password", "refresh_token") // 授权范围 backend 后端 .scopes("backend") // 可以设置对哪些资源有访问权限,不设置则全部资源都可以访问 .resourceIds("backend-resources") // 设置访问令牌的有效期,这里是 1 天 .accessTokenValiditySeconds(60 * 60 * 24) // 设置刷新令牌的有效期,这里是 30 天 .refreshTokenValiditySeconds(60 * 60 * 24 * 30); } ​ //定义jdbc模式 @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { // 客户端配置 clients.withClientDetails(jdbcClientDetailsService()); } ​
2.AuthorizationServerSecurityConfigurer

定义令牌的安全约束
一般定义允许客户端访问token,并允通过表单获取token

@Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security
                // 允许客户端访问 /oauth/check_token 检查 token
                .checkTokenAccess("isAuthenticated()")
                //允许客户端表单验证    
                .allowFormAuthenticationForClients();
    }

checkTokenAccess和allowFormAuthenticationForClients两个配完后客户端就可以不用通过预设的授权页面授权了,直接通过表单提交验证。
3.AuthorizationServerEndpointsConfigurer

定义授权,令牌端点,令牌服务。
一般用来定义授权模式,token存储模式。

 //  定义token的存储模式
@Bean
public TokenStore tokenStore() {
    //内存存储膜模式
    return new InMemoryTokenStore();
}
​
​
 @Bean
public TokenStore tokenStore() {
    // 基于 JDBC 实现,令牌保存到数据库
    return new JdbcTokenStore(dataSource());
}
​
​
//密码授权注入
@Autowired
private AuthenticationManager authenticationManager;
​
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    // 用于支持密码模式
    endpoints.authenticationManager(authenticationManager)
        //token存储模式
        .tokenStore(tokenStore());
}

逻辑

先定义授权访问方式 AuthorizationServerSecurityConfigurer 在定义 授权支持的模式和token存储方式 AuthorizationServerEndpointsConfigurer 最后 定义授权客户端/访问者的信息,如定义访问者,如果用内存模式
那么访问者的信息就都会存储在内存,如果定义在数据库,那么访问者的信息就都会在数据库,如定义客户端token的有效期等。
以上对应token的维护即授权, 先定义允许访问授权预设路径, 在定义token的模式和存储模式, 最后定义 token的属性。

2.WebSecurityConfigurerAdapter

对应 定义ouath2的配置
加密bean

供项目中加密用

  /**
     * @MethodName: passwordEncoder
     * @Description: 密码加密bean
     * @Param: []
     * @Return: org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
     * @Author: pl
     * @Date: 21:14
    **/
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        // 配置默认的加密方式
        return new BCryptPasswordEncoder();
    }

定义内存中的用户和初始化用户

 /**
     * @MethodName: userDetailsService
     * @Description: 这个bean用于为内存提供初始化用户
     * @Param: []
     * @Return: org.springframework.security.core.userdetails.UserDetailsService
     * @Author: pl
     * @Date: 21:05
    **/
    @Bean
    @Override
    protected UserDetailsService userDetailsService() {
        return new UserDetailsServiceImpl();
    }
   用户
/**
 * @Auther: pl
 * @Date: 2020/3/22 20:26
 * @Description:内存模式用户
 */
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
​
    private static final String USERNAME = "admin";
    private static final String PASSWORD = "$2a$10$WhCuqmyCsYdqtJvM0/J4seCU.xZQHe2snNE5VFUuBGUZWPbtdl3GG";
​
    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
        // 用户名匹配
        if (userName.equals(USERNAME)) {
            List<GrantedAuthority> grantedAuthorities = Lists.newArrayList();
            //授权USER角色   随便定义的角色
            GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("USER");
            grantedAuthorities.add(grantedAuthority);
            return new User(USERNAME, PASSWORD, grantedAuthorities);
        }
        // 用户名不匹配
        else {
            return null;
        }
    }
}
/**
 * @Auther: pl
 * @Date: 2020/3/22 20:26
 * @Description:jdbc模式用户
 */
@Service
public class UserDetailServiceImpl implements UserDetailsService {
    @Autowired
    private TbUserServiceImpl tbUserService;
    @Autowired
    private TbPermissionService tbPermissionService;
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        TbUser user = tbUserService.getUserByUserName(s);
        ArrayList<GrantedAuthority> grantedAuthorities = Lists.newArrayList();
        if (user!=null){
            List<TbPermission> tbPermissions = tbPermissionService.selectByUserId(user.getId());
            tbPermissions.forEach(tbPermission -> {
                SimpleGrantedAuthority grantedAuthority = new SimpleGrantedAuthority(tbPermission.getEnname());
                grantedAuthorities.add(grantedAuthority);
            });
            System.out.println("+++++++++++++++++++++++++++++++");
            return new User(user.getUsername(),user.getPassword(),grantedAuthorities);
        }
​
        return null;
    }
}
  初始化用户
 /**
     * @MethodName: configure
     * @Description: configure方法重写,用来增强。此处用于内存中初始化用户
     * @Param: [auth]
     * @Return: void
     * @Author: pl
     * @Date: 21:07
    **/
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService());
    }

定义oauth2模式

 /**
     * 用于支持 password 模式 ,ouath2有四种模式,本项目采用密码模式。
     *
     * @return
     * @throws Exception
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

忽略拦截

 /**
     * @MethodName: configure
     * @Description: 忽略拦截/user/login
     * @Param: [web]
     * @Return: void
     * @Author: pl
     * @Date: 23:16
    **/
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring()
                .antMatchers("/user/login");
    }

授权访问路径

  /**
     * @MethodName: configure
     * @Description: 授权
     * @Param: [http]
     * @Return: void
     * @Author: pl
     * @Date: 0:03
    **/
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.exceptionHandling()
                .and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                // 增加了授权访问配置   hasAuthority定义那些角色有这个路径访问权
                .antMatchers("/user/info").hasAuthority("USER")
                .antMatchers("/user/logout").hasAuthority("USER");
    }

上一篇 下一篇

猜你喜欢

热点阅读