笔记部分https://blog.csdn.net/feinifi/article/details/108123831
oauth2实验
-
pom
-
org.springframework.boot spring-boot-starter-security
-
-
当用户安装了上面maven就自己打开了验证功能,密码可以再login打开
-
@EnableWebSecurity和extends WebSecurityConfigurerAdapter即可自己配置securiyt的验证;
- public UserDetailsService userDetailsService()可以配置验证的账号和密码和权限
- public PasswordEncoder passwordEncoder()和上面搭配使用,密码加密功能,必须要,这个和上面已经可以正常使用登录验证功能了
- protected void configure(HttpSecurity http) throws Exception这个是用来对http请求进行过滤使用的
- hasAuthority("p1") 需要权限
- authenticated()需要验证
- permitAll()不需要验证
-
工作原理
-
用户提交用户名、密码被SecurityFilterChain中的 UsernamePasswordAuthenticationFilter 过滤器获取到, 封装为请求Authentication,通常情况下是UsernamePasswordAuthenticationToken这个实现类。
-
然后过滤器将Authentication提交至认证管理器(AuthenticationManager)进行认证
-
认证成功后, AuthenticationManager 身份管理器返回一个被填充满了信息的(包括上面提到的权限信息, 身份信息,细节信息,但密码通常会被移除) Authentication 实例。
-
SecurityContextHolder 安全上下文容器将第3步填充了信息的 Authentication ,通过 SecurityContextHolder.getContext().setAuthentication(…)方法,设置到其中。 可以看出AuthenticationManager接口(认证管理器)是认证相关的核心接口,也是发起认证的出发点,它 的实现类为ProviderManager。而Spring Security支持多种认证方式,因此ProviderManager维护着一个 List 列表,存放多种认证方式,最终实际的认证工作是由AuthenticationProvider完成的。咱们知道web表单的对应的AuthenticationProvider实现类为DaoAuthenticationProvider,它的内部又维护着一个UserDetailsService负责UserDetails的获取。最终AuthenticationProvider将UserDetails填充至Authentication
-
-
UserDetailsService 这个只能作为方法,或者被继承,二选一,而不能共存
-
http.sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
-
always 如果没有session存在就创建一个 ifRequired 如果需要就创建一个Session(默认)登录时 never SpringSecurity 将不会创建Session,但是如果应用中其他地方创建了Session,那么Spring stateless Security将会使用它。SpringSecurity将绝对不会创建Session,也不使用Session -
若使用stateless,则说明Spring Security对登录成功的用户不会创建Session了,你的应用程序也不会允许新建 session。并且它会暗示不使用cookie,所以每个请求都需要重新进行身份验证。这种无状态架构适用于REST API 及其无状态认证机制。
-
我们可以使用httpOnly和secure标签来保护我们的会话cookie:
- httpOnly:如果为true,那么浏览器脚本将无法访问cookie
- secure:如果为true,则cookie将仅通过HTTPS连接发送
-
验证加oauth2
-
pom
-
org.springframework.boot spring-boot-starter-security org.springframework.security.oauth spring-security-oauth2 2.3.4.RELEASE
-
-
- 1、根据用户名密码等参数直接获取token
接口:http://localhost:8080/oauth/token
参数:username password grant_type client_id client_secret redirect_uri
返回值:access_token
2、根据token,访问资源
接口:http://localhost:8080/api/test/hello
参数:access_token - 认证服务器配置(0)>资源服务器配置(3)>web安全服务配置(100)
- httpBasic 和 formLogin
- httpBasic 是http认证协议Basic auth 验证才可以访问,或者在请求头加上Authorization:Basic 加密后用户名:密码
- formLogin 使用表单验证,采用post方法,也可以退出登录.
- httpBasic 是没有login接口系列,要自主加上formLogin方法才有
- httpBasic 适合只有http请求,formLogin适合有web页面展示,就是后台管理,可以同时存在
- 授权 自家app myapp 别家app otherapp 都是别人想要我的其中一个服务,hello
- 授权码模式
- otherapp 带上请求,访问myapp
- http://myappurl/oauth/authorize?response_type=code(授权模式)&state=123456(非必须)&client_id=client(客户端id)&scope=all(请求范围)&redirect_uri=http://otherappurl
- 返回http://otherappurl?code=ycjU3F&state=123456可以拿到ycjU3F这个code
- 然后请求http://myappurl/oauth/token?client_id=client(客户端id)&client_secret=secret(密钥)&grant_type=authorization_code(在clients中定义)&code=ycjU3F&redirect_uri=http://otherappurl这个请求可以是post也可以是get然后会返回
- {
“access_token”: “2311e499-bd15-4eee-a718-0edb113e71ef”,
“token_type”: “bearer”,
“refresh_token”: “b920b1ad-1083-428a-9762-fe549e358fee”,
“expires_in”: 1171,
“scope”: “all”
} - 将参数带上请求可以访问的地方http://myapp?access_token=2311e499-bd15-4eee-a718-0edb113e71ef必须有权限才行
- 密码模式
- 与上面的授权码模式唯一不同就是需要改变grant_type,减去code,然后加上username和password参数即可http://myother/oauth/token?client_id=client&client_secret=secret&grant_type=password&redirect_uri=http://example.com&username=admin&password=123
- 授权码模式
web配置
@EnableWebSecurity
@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected UserDetailsService userDetailsService() {
InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
inMemoryUserDetailsManager.createUser(User.withUsername("admin").password(passwordEncoder().encode("123")).roles("admin").build());
inMemoryUserDetailsManager.createUser(User.withUsername("user").password(passwordEncoder().encode("123")).roles("user").build());
return inMemoryUserDetailsManager;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
//使用basic加密 需要在请求头加上Authorization: Basic 加密后的username:password
.httpBasic()
.and()
.authorizeRequests()
.antMatchers("/oauth
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@PostConstruct
public void init(){
// System.out.println("123密码加密后密码 ↓↓↓↓↓ ");
// System.out.println(passwordEncoder().encode("123"));
}
}
资源服务
@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/admin
@Configuration
@EnableAuthorizationServer
public class AuthServerConfiguration extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
// 密码模式下配置认证管理器 AuthenticationManager
endpoints.authenticationManager(authenticationManager);
endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET,HttpMethod.POST);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.realm("oauth2-resources")
// 开启/oauth/token_key验证端口无权限访问
.tokenKeyAccess("permitAll()")
// 开启/oauth/check_token验证端口认证权限访问
.checkTokenAccess("isAuthenticated()")
// 允许客户表单认证
.allowFormAuthenticationForClients();
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
// client_id
.withClient("client")
// client_secret
.secret(passwordEncoder.encode("secret"))
.redirectUris("http://example.com")
// 授权类型
.authorizedGrantTypes("authorization_code","password","refresh_token","implicit","client_credentials")
// 授权范围
.scopes("all")
// 登录后绕过批准询问(/oauth//confirm/i_access)
.autoApprove(true)
.resourceIds("oauth2-resource")
.accessTokenValiditySeconds(1200)
.refreshTokenValiditySeconds(50000);
}
}
用户连接数据库
@Service
public class SpringDataUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//登录账号
System.out.println("username="+username);
//根据账号去数据库查询...
// 这里暂时使用静态数据
UserDetails userDetails = User.withUsername(username).password("123").authorities("p1").build();
return userDetails;
}
}
public void configure(HttpSecurity http)
如果哪个过滤器匹配到url,下个过滤器就会失效
antMatchers 匹配一个或者多个请求
anyRequest 匹配剩下所有请求
antMatcher()和authorizeRequests().antMatchers()。----表示此过滤器,只拦截一个或者多个并且验证.
permitAll(). ---- 放行
.anyRequest().authenticated()----请求会被其他过滤器拦截



