PAcee Hub

学习 笔记


  • 首页

  • 标签

  • 分类

SpringSecurity21-授权管理

发表于 2020-01-21 | 分类于 springsecurity

权限控制简单介绍

在我们之前的20篇关于SpringSecurity的笔记中,较详细的介绍了SpringSecurity关于认证的内容,接下来我们会讲一下关于授权的内容。

认证是指:你有一个家,你可以进行控制让谁能进来,比如你的家人,谁进不来比如陌生人,这就是认证。

授权是指:你的家人进到你家可以做什么事,比如你姑姑姨姨就不能随便翻你的东西,打开保险柜,而你的妻子就可以,这就是授权。

对于我们开发应用的授权有一定经验的都知道,基本适用于后台管理系统,不同职位的人有不同的操作权限,比如人事就有添加员工的权限,财务有设置工资的权限,领导有审批请假的权限等等。

那么一般情况下,如何控制授权呢?这里不止SpringSecurity

在这里插入图片描述

如图,系统应该有两部分信息

  • 系统配置:哪些路径需要哪些权限才可以访问,比如添加用户需要A权限,审批需要B权限
  • 用户权限配置:哪些用户具有哪些权限,比如人事有A权限但是没有B权限,领导既有A还有B权限

当请求发过来的时候,会先根据系统配置看看这个请求是否需要某个权限才能访问,如果有,再判断用户是否有这个权限,有才能访问。

SpringSecurity简单权限控制

对于某些URL,只有某些权限的用户才能访问,这种逻辑直接写死在代码里,从技术实现上来说很简单,但真实项目中应该很少会这样用,但本文仍主要来演示一下具体的代码实现。

首先我们把demo项目改为引用browser

然后我们看一下之前的代码:

1579573798751

可以看到,这些都是和认证有关的,关于授权就是.permitAll(),意思是这些请求返回True,对于其他的授权控制代码也类似,如下:

阅读全文 »

SpringSecurity20-OAuth-JWT

发表于 2020-01-20 | 分类于 springsecurity

基本的Token配置

在之前的OAuth学习中,我们都是使用它默认生成的Token,那么我们这一节就是来自定义Token的一些配置。

配置Token

配置Token需要继承AuthorizationServerConfigurerAdapter类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private UserDetailsService myUserDetailService;
@Autowired
private PasswordEncoder passwordEncoder;

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
// 如果继承AuthorizationServerConfigurerAdapter这个类,就必须配置下面两个对象
// 认证管理器和UserDetailsService
// Security5之后,认证管理器无法自动注入,需要向容器中添加,方式为继承WebServerConfigurerAdapter重新方法
endpoints.authenticationManager(authenticationManager)
.userDetailsService(myUserDetailService);

}

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("enbuys") // client id
// client secret 必须使用密码进行加密
.secret(passwordEncoder.encode("enbuys"))
// token过期时间
.accessTokenValiditySeconds(6000)
// 可以使用的授权模式
.authorizedGrantTypes("password","refresh_token")
// 配置授权类型,设置了这个,发送请求如果不同会报错
.scopes("all")
.and() // 配置第二个客户端
.withClient("test")
.secret(passwordEncoder.encode("test"))
;
}

}

由代码注释可见,继承此类,必须重写方法配置AuthorizationManager和UserDetailsService,其中UserDetailsService我们之前已经实现,直接注入即可,AuthorizationManager在SpringBoot2.x,Security5.x之后需要我们向容器注入,否则会出现无法找到类的情况,所以我们下一步需要向容器注入AuthorizationManager。

还有一点需要注意的是,在SpringBoot2.x,Security5.x之后,客户端密码即clientSecret需要进行加密,不然无法匹配。

阅读全文 »

SpringSecurity19-OAuth-重构三种登录

发表于 2020-01-19 | 分类于 springsecurity

为何/如何重构表单登录

首先,我们需要明确一点,为什么我们要重构之前的表单登录?

因为对于App来说,没有Cookie,所以不能使用Cookie+Session的方式对登录用户信息存储,就必须使用Token,然后SpringSecurityOAuth就是封装了一系列操作,最后返回Token,但是它只有四种授权模式,并没有直接表单登录,或者短信登录的方式,所以我们需要进行一些改变,来通过SpringSecurityOAuth帮我们实现Token的生成发放,最后实现App的登录以及登录状态保存。

通过上一节的学习,我们大致了解了SpringSecurityOAuth生成Token的流程,如下图

1579419496431

那么,我们要用的逻辑是哪块呢?就是最下面AuthorizationServerTokenServices生成Token的逻辑,所以我们的实现流程就如下图:

在这里插入图片描述

首先我们之前的认证成功处理器的处理就是直接将Authorization作为json形式返回,所以我们是有Authorization这个对象的。

那么我们的目光就聚焦在OAuth2Request上了,只要有了他就能调用DefaultTokenServices生成Token,那么如何创建一个OAuth2Request对象呢?

通过上节源码可知,它是由ClientDetails和TokenRequest生成的

  • ClientDetails是由请求参数ClientId作为参数,调用ClientDetailsService生成的
  • TokenRequest就更简单了,是直接new出来的,通过请求的几个参数和ClientDetails

总结,使用SpringSecurity OAuth重构表单登录的思路有三点:

  • 代码写在AuthorizationSuccessHandler成功处理器里
  • 最终目标是构建出OAuth2Request对象
  • 构建对象需要从参数ClientId入手
    阅读全文 »

SpringSecurity18-OAuth-源码解析

发表于 2020-01-19 | 分类于 springsecurity

明确目标

还记得我们刚了解OAuth时说的,它默认只有四种认证模式,那么如果我们想用短信验证或者第三方登录验证的模式,如何自定义授权模式并嫁接到认证服务器中呢?

在这里插入图片描述

即我们自己实现认证方式,然后使用Security造好的Token生成存放校验逻辑进行Token管理

为了达到这个目的,我们需要对SpringSecurity OAuth源码进行解析

源码解析

TokenEndPoint

首先,在我们上一章中,获取令牌的方式是向/oauth/token发送post请求,根据我们对springboot的了解,这个是由EndPoint端点控制的,所以我们直接取看TokenEndPoint源码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class TokenEndpoint extends AbstractEndpoint {
@RequestMapping(value = "/oauth/token", method=RequestMethod.POST)
public ResponseEntity<OAuth2AccessToken> postAccessToken(Principal principal, @RequestParam
Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {

if (!(principal instanceof Authentication)) {
throw new InsufficientAuthenticationException(
"There is no client authentication. Try adding an appropriate authentication filter.");
}
// 从请求中获取clientId
String clientId = getClientId(principal);
// 根据clientId,获取ClientDetails,保存了clientId,secret,scope等客户端配置的信息
ClientDetails authenticatedClient = getClientDetailsService().loadClientByClientId(clientId);

// 通过ClientDetails获取TokenRequest,其中保存grantType,username,password等就是我们请求中的那些必要参数,封装成TokenRequest对象
TokenRequest tokenRequest = getOAuth2RequestFactory().createTokenRequest(parameters, authenticatedClient);

··· // 进行一些校验,比如scope是否合法,授权模式判断等

// 生成Token的步骤
OAuth2AccessToken token = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest);
if (token == null) {
throw new UnsupportedGrantTypeException("Unsupported grant type: " + tokenRequest.getGrantType());
}

return getResponse(token);

}
}
阅读全文 »

SpringSecurity17-OAuth-实现标准的OAuthProvider

发表于 2020-01-19 | 分类于 springsecurity

准备工作

我们之前的项目中,都是使用的都是demo模块依赖Browser模块,对于SpringSecurityOAuth来说,我们需要使用app模块,所以我们要进行一些配置

demo模块的依赖引用由browser改为app

1
2
3
4
5
<dependency>
<groupId>com.enbuys</groupId>
<artifactId>spring-security-app</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

core中使用到了认证失败处理器和认证成功处理器,所以要从browser移到app中,对应着SimpleResponse也要移动

将我们自己实现的UserDetailsService放到Demo模块中

实现Provider中的认证服务器

对于SpringSecurity OAuth来说,实现认证服务器非常简单,因为由上节我们知道,很多东西他都已经封装好了,比如四种认证模式,Token生成规则,返回的实现等等。

代码实现

所以我们只需创建一个类,添加注解即可实现标准的认证服务器

1
2
3
4
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig {
}

这样一个认证服务器就创建好了,然后启动应用

1579399724850

在控制台可以看到Security向容器中添加了一些控制器,

  • /oauth/authorize:就是授权码模式授权的接口,访问这个接口就会跳转到授权页面,就比如QQ登录时的那个登录页
  • /oauth/token:根据授权码获取AccessToken的接口

在下面还可以看懂自动生成的client-id与secret,因为是随机生成的,所以很不方便,我们这里配置成固定的

1
2
security.oauth2.client.client-id=enbuys
security.oauth2.client.client-secret=enbuys
阅读全文 »

SpringSecurity16-OAuth-基本介绍

发表于 2020-01-17 | 分类于 springsecurity

SpringSecurityOAuth简单介绍

Token Session Cookie

了解SpringSecurityOAuth之前,我们先说说Session,Cookie和Token。

Session和Cookie大家都不陌生,Session存在服务端类似Map,保存用户信息,Cookie是Session生成的,创建后给浏览器保存,存放的是JSESSIONID与SessionId的键值对

我们再说说看Token,Token就是在用户登陆后,由服务端通过一系列规则制造的一个对象,与用户信息绑定起来,然后存放在内存或数据库中,同时返回给浏览器。

注意,这里返回给浏览器,有很多种形式,比如保存在请求头或参数或者url里都可以,并没有cookie那么局限,服务器就可以通过请求中的token来判定这些请求是该用户的请求。

那么,Token的好处是什么?

  • 首先Cookie是基于浏览器的,如果不使用浏览器而是手机APP那么Cookie就不复存在的,就只能使用Token了
  • 还有一个问题就是安全,如果被人知道了某个用户的SessionId,伪造一个Cookie发请求,就会出现安全问题,而Token因为认证创建方式都是由我们自己定义的,安全性相对更高。
    阅读全文 »

SpringSecurity15-Session管理与退出登录

发表于 2020-01-16 | 分类于 springsecurity

本篇内容概述

在前面的笔记中,我们学习了表单登录,短信验证码,图片验证码,以及Social实现的第三方QQ,微信登录,而这些的实现都依靠SpringSecurity

但是我们以前没有使用SpringSecurity,是如何实现登录的呢?是放在Session中保存用户信息的。其实SpringSecurity也是一样,底层也是依靠Session来保存它定义的用户信息。

这一章我们就要讲讲SpringSecurity中Session的管理,主要有三点

  • Session超时处理
  • Session并发控制
  • 集群Session的管理

除了Session管理,我们还要讲一下退出登录,SpringSecurity会自动帮我们做很多退出后需要做的事

  • 如何退出登录
  • SpringSecurity默认的退出逻辑
  • 退出登录的相关配置

Session超时处理

超时时间处理

首先是设置Session超时时间,这个很常用了,因为是SpringBoot项目,所以直接在配置文件中设置

1
2
3
# 设置Session失效时间
#spring.session.timeout=60s # springboot1.x
server.servlet.session.timeout=60s
阅读全文 »

SpringSecurity14-Social-绑定和解绑

发表于 2020-01-16 | 分类于 springsecurity

本篇内容概述

在很多网站,你注册了他们的用户后,在个人信息页面具有第三方登录的绑定和解绑功能,这和我们之前学习的第三方直接登录大同小异,不同点就是绑定与解绑需要先注册登录再操作,而之前是直接使用第三方登录再注册。

1579139392085

我们这一章要学习的就是使用SpringSocial实现第三方登录的绑定与解绑,实现功能有以下三个

  • 获取用户绑定信息,获取了信息,前端页面才能展示绑定按钮还是解绑按钮
  • 绑定第三方账号
  • 解绑第三方账号

注意:因为对于QQ的绑定,需要到QQ互联中设置回调地址,比较麻烦,这里我们就使用微信进行绑定解绑操作

ConnectController

实现功能之前,我们要先学习这个类,也是SpringSocial提供关于绑定的最重要的一个类,它提供了我们上面所需实现功能,如下

获取用户信息接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Controller
@RequestMapping("/connect")
public class ConnectController implements InitializingBean {
@RequestMapping(method=RequestMethod.GET)
public String connectionStatus(NativeWebRequest request, Model model) {
setNoCache(request);
processFlash(request, model);
Map<String, List<Connection<?>>> connections = connectionRepository.findAllConnections();
model.addAttribute("providerIds", connectionFactoryLocator.registeredProviderIds());
model.addAttribute("connectionMap", connections);
return connectView();
}

protected String connectView() {
return getViewPath() + "status";
}
}

通过源码可知,我们只需发送GET请求到/connect上,即可获取当前登录用户的绑定信息

注意这里会返回connectView()方法,即返回视图,所以我们需要创建一个名字叫/connect/status的视图对象,注入到容器中,不然会抛出405错误

实现原理也很简单,先通过UsersConnectionRepository根据userId查userconnection表,然后获取容器中所有ConnectFactory,然后根据ProviderId与查出来的结果进行判断,就可以知道是否绑定了

阅读全文 »

SpringSecurity13-Social-微信登录

发表于 2020-01-15 | 分类于 springsecurity

微信登录实际流程和QQ差不多,就是其获取接口入参和出差不同,所以需要进行一些修改

主要的配置有:

  • Properties
  • API
  • OAuth2Operation
  • ServiceProvider
  • ConnectionFactory
  • AutoConfiguration

这里不光针对微信,对于其他的第三方登录也是一样

微信Properties

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
@ConfigurationProperties("enbuys.weixin.security")
public class WeixinProperties {
private String providerId = "weixin";

private String appId;

private String appSecret;

private String filterProcessesUrl;

public String getFilterProcessesUrl() {
return filterProcessesUrl;
}

public void setFilterProcessesUrl(String filterProcessesUrl) {
this.filterProcessesUrl = filterProcessesUrl;
}

public String getProviderId() {
return providerId;
}

public void setProviderId(String providerId) {
this.providerId = providerId;
}

public String getAppId() {
return appId;
}

public void setAppId(String appId) {
this.appId = appId;
}

public String getAppSecret() {
return appSecret;
}

public void setAppSecret(String appSecret) {
this.appSecret = appSecret;
}
}

和QQ一模一样

阅读全文 »

springSecurity12-Social-QQ登录(下)

发表于 2020-01-15 | 分类于 springsecurity

本篇内容概述

上一章末尾说过,由于这里的注册其实是从第三方登陆过程中重定向而来的注册,因此这种情况下的注册肯定与普通的用户注册有一定的区别。都要有哪些区别呢?其实主要在两块:

一块是上篇文章说的当用户注册完,肯定要与该第三方(即QQ、微信等)建立起关系,也就是说下次用户直接用QQ或微信等进行登陆,那肯定直接就可以登陆了。落实到代码上,就是用户注册完,需要同时往userconnection表里插入一条数据。

第二块在于注册页面的展示与逻辑。下面是我直接在当当网进行QQ登陆时导向的注册页面,我们可以看到人家在这种情况下的注册页面里就不光有注册功能,还同时把从QQ获取到的你的头像和昵称信息给显示了出来,让你有种亲切感。

在这里插入图片描述

其实大家除了见过像当当这种直接点击QQ登陆进行登陆,由于没有进行注册或绑定过,而被导向一个用户注册页面的网站,肯定也见过那种从来就没上过的网站直接点击QQ登陆或者微信登陆,但是却可以直接登陆成功而不需要注册的网站,而且很多。那这种又是怎么弄得呢?这一块也是本文需要讲解的内容。
因此,本文将主要讲解如下三块内容:

  • 第三方登陆时用户注册页面如何拿到QQ头像和昵称等信息
  • 用户注册时如何将QQ与用户信息建立关联,插入userconnection表
  • 第三方登陆时,如何跳过注册逻辑
    阅读全文 »
12…8 >
PAcee

PAcee

学习 笔记

76 日志
6 分类
7 标签
© 2020 PAcee