令牌的表现形式就是一个字符串
文章目录
- 服务提供商的实现
- 认证服务器
- demo pom 文件中引入app模块依赖 使正常启动
- 实现认证服务器
- WhaleAuthenticationSecurityConfig
- 授权码模式的请求参数
- User must be authenticated with Spring Security before authorization can be completed.
- MySecurityConfig
- DemoUserDetailsService
- 期间有出现一个错误This application has no explicit mapping for /error, so you are seeing this as a fallback.
- error="invalid_request", error_description="At least one redirect_uri must be registered with the client
- 授权码授权流程
- 再看密码模式
- 资源服务器的实现
实现一个标准的oauth2协议中的provider角色的主要功能
重构之前的认证方式的代码,使其支持token
高级特性
服务提供商的实现
认证服务器
资源服务器
认证服务器
demo pom 文件中引入app模块依赖 使正常启动
<!--<dependency>-->
<!--<groupId>com.whale.security</groupId>-->
<!--<artifactId>whale-security-browser</artifactId>-->
<!--<version>${whale.security.version}</version>-->
<!--</dependency>-->
<dependency>
<groupId>com.whale.security</groupId>
<artifactId>whale-security-app</artifactId>
<version>${whale.security.version}</version>
</dependency>
注释掉session的配置
重新启动
Message: Error creating bean with name 'validateCodeFilter': Unsatisfied dependency expressed through field 'authenticationFailureHandler'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.security.web.authentication.AuthenticationFailureHandler' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
2019-05-20 13:58:01.564 INFO 11352 --- [ main] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
没有找到失败处理器
因为之前的在browser模块里面
在app模块里面重新创建失败处理器
先直接把browser里面的这两个失败 成功处理器拷贝到app,并引入相关类
重新启动
Error creating bean with name 'myUserDetailsService': Unsatisfied dependency expressed through field 'passwordEncoder';
@Configuration
@EnableConfigurationProperties(SecurityProperties.class)//使SecurityProperties中的配置生效
public class SecurityCoreConfig {
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();//也可以自定义 只要实现PasswordEncoder接口
}
}
再次重新启动
已经正常启动起来
实现认证服务器
WhaleAuthenticationSecurityConfig
@Configuration
@EnableAuthorizationServer
public class WhaleAuthenticationSecurityConfig {
}
这样就已经实现了一个认证服务器
可以提供oauth的四种授权模式
重新启动
控制台有如下几个路径
直接访问报错
授权码模式的请求参数
这还需要一些参数
https://oauth.net/2/
https://tools.ietf.org/html/rfc6749
查看授权码模式
https://tools.ietf.org/html/rfc6749#page-24
它需要如下几个请求参数
client_Id 启动的时候会在控制台打印出来
其中client_id 和 client_secret 每次启动都会自动变化
demo application 配置下
security.oauth2.client.client-id=whale
security.oauth2.client.client-secret=123456
User must be authenticated with Spring Security before authorization can be completed.
构造请求参数重新请求
http://127.0.0.1:8080/oauth/authorize?response_type=code&client_id=whale&redirect_uri=http://example.com&scope=all
报错
org.springframework.security.authentication.InsufficientAuthenticationException: User must be authenticated with Spring Security before authorization can be completed.
根据这个路径找发到这个方法
AuthorizationEndpoint
@RequestMapping(value = "/oauth/authorize")
public ModelAndView authorize(Map<String, Object> model, @RequestParam Map<String, String> parameters,
SessionStatus sessionStatus, Principal principal) {
// Pull out the authorization request first, using the OAuth2RequestFactory. All further logic should
// query off of the authorization request instead of referring back to the parameters map. The contents of the
// parameters map will be stored without change in the AuthorizationRequest object once it is created.
AuthorizationRequest authorizationRequest = getOAuth2RequestFactory().createAuthorizationRequest(parameters);
try {
·················································
if (!(principal instanceof Authentication) || !((Authentication) principal).isAuthenticated()) {
throw new InsufficientAuthenticationException(
"User must be authenticated with Spring Security before authorization can be completed.");
}
················································
}
catch (RuntimeException e) {
sessionStatus.setComplete();
throw e;
}
}
方法里有个if语句,它是判断我们当前有没有登录,我打断点过去发现principal为null
结合错误提示,是想让我们登录
我随便访问一个地址http://localhost:8080/hello 竟然不需要登录,我百思不得题姐
注释掉WhaleAuthenticationSecurityConfig
这个认证服务器的配置类,就又需要登录了
看来原因就是出在这个类上,配置了认证服务器原来的安全认证就失效了吗?
之前项目依赖browser模块时有一个BrowserSecurityConfig
继承了WebSecurityConfigurerAdapter
现在依赖app了 我在demo下重新写一个WebSecurityConfigurerAdapter
的实现
MySecurityConfig
@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Qualifier("demoUserDetailsService")
@Autowired
private UserDetailsService userDetailsService;
@Override
public void configure(HttpSecurity http) throws Exception {
http.formLogin() //指定身份认证的方式为表单登录
.and()
.authorizeRequests() //对请求授权
.anyRequest() //任何请求
.authenticated() //安全认证
.and().userDetailsService(userDetailsService);
}
}
DemoUserDetailsService
@Component
public class DemoUserDetailsService implements UserDetailsService{
// 这里注入dao 层 用于查询数据库
Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
//根据用户名从数据库查找用户信息
logger.info("UserDetails 登录用户名"+ userName);
String password = passwordEncoder.encode("123456");
return new User(userName, password,
AuthorityUtils.commaSeparatedStringToAuthorityList("admin,ROLE_USER"));//第三个参数是做授权的
}
期间有出现一个错误This application has no explicit mapping for /error, so you are seeing this as a fallback.
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
There was an unexpected error (type=Forbidden, status=403).
Access Denied
因为在springboot中所有的类不能和启动类同级
error=“invalid_request”, error_description="At least one redirect_uri must be registered with the client
再次重新启动访问请求连接又报错 也是醉了
OAuth Error
error="invalid_request", error_description="At least one redirect_uri must be registered with the client."
打断点
AuthorizationEndpoint /oauth/authorize里面
DefaultRedirectResolver
registeredRedirectUris 为null 所至
解决
https://blog.csdn.net/taotaojs/article/details/85126140 这个不能解决
https://segmentfault.com/q/1010000015995274/a-1020000015998139 ok
其他
https://www.cnblogs.com/cjsblog/p/9296361.html
https://alexbilbie.com/guide-to-oauth-2-grants/
https://docs.spring.io/spring-security-oauth2-boot/docs/current-SNAPSHOT/reference/htmlsingle/
https://blog.csdn.net/qq_36144258/article/details/79413485
https://blog.csdn.net/u013815546/article/details/76898524
https://segmentfault.com/a/1190000012260914
在demo application中加入
security.oauth2.client.registered-redirect-uri=http://example.com
再次启动 重新访问 成功了
授权码授权流程
点击授权
这时已经跳转到第三方应用了
第三方应用应该拿着这个授权码去获取token post 访问 /oauth/token
post 访问 /oauth/token
先修改MySecurityConfig 的登录方式为 httpBasic()
然后用postman 验证一下
ok
https://tools.ietf.org/html/rfc6749#page-24
/oauth/token的访问
注意请求参数中的code为我们的授权码
安全认证为
如下
{
"access_token": "7b4c3f66-d3b4-4035-b46c-41a5f1ff0b26",
"token_type": "bearer",
"refresh_token": "9e1a166e-492d-4ad7-b9c2-b4bd36336f2a",
"expires_in": 43199,
"scope": "all"
}
此时 oauth2的授权码流程已经走完
再看密码模式
https://tools.ietf.org/html/rfc6749#page-24
其中 basic 的认证还是需要的
还需要服务提供商的用户和密码
但它不知道你的用户名和密码是怎么来得
发送请求报错Unsupported grant type: password
Unsupported grant type: password
解决
https://segmentfault.com/a/1190000012260914
MySecurityConfig中
@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Qualifier("demoUserDetailsService")
@Autowired
private UserDetailsService userDetailsService;
@Override
public void configure(HttpSecurity http) throws Exception {
http.httpBasic() //指定身份认证的方式为表单登录
.and()
.authorizeRequests() //对请求授权
.anyRequest() //任何请求
.authenticated() //安全认证
.and().userDetailsService(userDetailsService);
}
/**
* 需要配置这个支持password模式
* support password grant type
* @return
* @throws Exception
*/
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
再次发送请求 成功
{
"access_token": "6eb99d87-38da-45af-aca5-093628bc6fa0",
"token_type": "bearer",
"refresh_token": "829cdf29-06cf-45d4-82ae-789dde24b757",
"expires_in": 43199,
"scope": "all"
}
注意对于已经请求过token的用户在有效期内再次请求时 ,请求的token字符串是一样的
资源服务器的实现
@Configuration
@EnableResourceServer
public class WhaleResourceServerConfig {
}
此时我们这个服务器既是认证服务器又是资源服务器
启动访问 restlet client 工具访问 http://127.0.0.1:8080/hello
401错误
{"error":"unauthorized","error_description":"Full authentication is required to access this resource"}
么有做身份认证
请求时需要把token带着
重新用密码授权模式获取token
请求头中加入要加入
“access_token": “09ed8d75-cfeb-4c84-939c-19bf8559e011”,
“token_type”:”bearer“
请求头如下
Authorization bearer 09ed8d75-cfeb-4c84-939c-19bf8559e011
注意token_type和access_token之间有一个空格
它就是通过这个access_token来确认身份