创建认证服务auth
(1)引入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-jwt</artifactId>
<version>1.1.1.RELEASE</version>
</dependency>
第一步、创建配置类
自定义配置类OAuth2AuthorizationServer,继承AuthorizationServerConfigurerAdapter,添加注解
@Configuration
@EnableAuthorizationServer
@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServer extends AuthorizationServerConfigurerAdapter {
}
重写AuthorizationServerConfigurerAdapter中的三个方法,配置授权服务器
public class AuthorizationServerConfigurerAdapter implements AuthorizationServerConfigurer {
public AuthorizationServerConfigurerAdapter() {
}
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
}
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
}
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
}
}
这三个方法的作用:
ClientDetailsServiceConfigurer:
配置客户端信息,客户端信息在这里进行初始化,可以在这里写死也可以通过数据库来存储和调取
AuthorizationServerEndpointsConfigurer:
配置令牌服务和令牌的访问端点
AuthorizationServerSecurityConfigurer:
配置令牌端点的安全约束
第二步、配置客户端信息
配置客户端信息的 主要配置项:
clientId:客户端id
secret: 客户端秘钥
scope:允许的授权范围
authorizedGrantTypes:允许客户端使用的授权类型
authorities:客户端可以使用的权限
客户端信息 能够在应用程序运行的时候进行更新 可以使用内存存储也可以存储在关系型数据库中
接下来演示用内存的方式存储客户端信息,配置如下:
/**
* 配置基于内存或JDBC的客户端信息
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()// 使用内存存储
.withClient("c1")//客户端id
.secret(new BCryptPasswordEncoder().encode("secret"))//客户端秘钥
.resourceIds("res1")//资源列表
/**
* 允许给客户端授权的5种授权类型:
* 1 "authorization_code" 授权码模式, 2 "password" 密码模式, 3 "client_credentials" 客户端模式
* 4 "implicit" 隐式模式, 5 "refresh_token" 刷新令牌
*/
.authorizedGrantTypes("authorization_code","password","client_credentials","implicit","refresh_token")
.scopes("all")//允许的授权范围
.autoApprove(false) //false: 如果是授权码模式 跳转到授权页面
.redirectUris("http://www.baidu.com");//加上验证回调地址
}
3、令牌服务底层实现原理
(1)底层源码分析:
AuthorizationServerTokenServices接口定义了一些操作使得你可以对令牌进行一些必要的管理;
DefaultTokenServices是AuthorizationServerTokenServices的实现类,可以使用它来设置令牌的格式和令牌的存储;
默认创建一个令牌时,使用随机值进行填充,除了持久化令牌是委托一个TokenStore接口来实现以外,其他功能都由DefaultTokenServices实现;
TokenStore这个接口有一个默认的实现类InMemoryTokenStore,如其命名,所有的令牌都被保存在了内存中。
(2)TokenStore的3个实现类简介:
InMemoryTokenStore:该实现类被默认采用,这种方式是将令牌保存到内存中,可以在开发阶段使用它做调试;
JdbcTokenStore:这是一个基于JDBC的实现类,令牌会被保存进关系型数据库。这种实现方式可以在不同的服务器之间共享令牌信息,使用该实现类要导入spring-jdbc依赖
JwtTokenStore:它可以把令牌相关的数据进行编码,不需要进行存储
4、令牌服务代码实现
@Autowired
ClientDetailsService clientDetailsService;
@Autowired
TokenStore tokenStore;
@Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
@Bean
public AuthorizationServerTokenServices tokenServices() {
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setClientDetailsService(clientDetailsService);
tokenServices.setSupportRefreshToken(true);
tokenServices.setTokenStore(tokenStore);
tokenServices.setAccessTokenValiditySeconds(7200); //令牌默认有效期2小时
tokenServices.setRefreshTokenValiditySeconds(259200); //刷新令牌默认有效期3天
return tokenServices;
}
5、令牌访问端点配置
(1)配置授权类型
authenticationManager:
用于密码授权模式
authorizationCodeServices:
用于授权码模式
implicitGrantService:
用于设置隐式授权模式
userDetailsService:
配置自定义的userDetailsService实现类
tokenGranter:
四种授权模式不满足需求的情况下,做扩展增强
https://www.toobug.cn/post/2865.html
(2)配置授权端点的URL:
我们可以通过AuthorizationServerEndpointsConfigurer 对象的 pathMapping() 方法来配置端点URL链接,它有两个参数:
第一个参数:String 类型,它是这个端点URL的默认链接
第二个参数:String 类型,它是你要替换的URL链接
框架的默认URL链接如下:
/oauth/authorize:授权端点
/oauth/token:令牌端点
/oauth/confirm_access:用户确认授权提交端点
/oauth/error:授权服务错误信息端点
/oauth/check_token:用于资源服务访问的令牌解析端点
/oauth/token_key:如果使用的是JWT令牌,则为 提供公有密匙的端点
需要注意的是授权端点这个URL应该被spring security保护起来,只供授权用户访问
6、配置令牌端点的安全约束
AuthorizationServerSecurityConfigurer用来配置令牌端点的安全约束,配置如下:
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security
//tokenkey端点完全公开
.tokenKeyAccess("permitAll()")
//checkToken端点完全公开
.checkTokenAccess("permitAll()")
//允许表单认证
.allowFormAuthenticationForClients();
}
web安全配置
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* 为特定的Http请求配置基于Web的安全约束
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
//关闭csrf
http.csrf().disable()
//不通过Session获取SecurityContext
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
//对于登录接口,允许匿名访问
.antMatchers("/user/login").anonymous() //匿名访问(未登录可访问,登录后不可访问)
.antMatchers("/user/hello").hasAuthority("system:test:index")
.anyRequest().authenticated();
//允许跨域
http.cors();
}
/**
* 实例化AuthenticationManager对象,将它注入spring容器
*/
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}