Spring Security 单体应用(认证授权服务+资源服务)
Spring Security 单体应用(认证授权服务+资源服务)
有了前面几篇文章的理论支持,是时候上实战了。
首先以单体的视角来进行集成,也就是认证服务和资源服务在一起,是一个单体项目。
环境
父类 pom 控制所有依赖版本。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.4</version>
<relativePath/>
</parent>
<properties>
<java.version>11</java.version>
<spring-boot.version>2.3.2.RELEASE</spring-boot.version>
<spring-cloud.version>Hoxton.SR9</spring-cloud.version>
<spring-cloud-alibaba.version>2.2.5.RELEASE</spring-cloud-alibaba.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- spring cloud alibaba 依赖 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- spring cloud 依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
子类依赖主要是spring-boot-starter-web
和spring-security-oauth2-autoconfigure
。
通过微服务版本限定后spring-security-oauth2-autoconfigure
的最终版本自动适配为2.1.2。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--安全模块-->
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
</dependency>
<!--server-api-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
</dependencies>
授权配置和测试
需要什么配置就写什么配置,主要是梳理流程。
1、授权服务核心配置
AuthorizationServerConfig
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
}
2、Spring Security 核心配置
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
}
3、访问测试
任意输入账号密码,会提示账号或密码错误。
4、完善配置
WebSecurityConfig
,因为重点是在于梳理流程,所以用户信息使用硬编码方式。
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Autowired
public PasswordEncoder passwordEncoders() {
return new BCryptPasswordEncoder();
}
@Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
// 配置全局用户信息
auth.inMemoryAuthentication().withUser("admin")
.password(passwordEncoders().encode("123456"))
.authorities(AuthorityUtils.commaSeparatedStringToAuthorityList("user_add,user_update,ROLE_ADMIN"));
}
AuthorizationServerConfig
,授权服配置端点信息。
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// 基于内存便于测试,使用in-memory存储
clients.inMemory()
// client_id
.withClient("rcbb")
// 未加密
//.secret("secret")
// 加密
.secret(passwordEncoder.encode("rcbb"))
// 资源列表
//.resourceIds("res1")
// 该client允许的授权类型authorization_code,password,refresh_token,implicit,client_credentials
.authorizedGrantTypes("authorization_code", "password", "client_credentials", "implicit", "refresh_token")
// 允许的授权范围
.scopes("all", "ROLE_ADMIN", "ROLE_USER")
// false跳转到授权页面
//.autoApprove(false)
//加上验证回调地址
.redirectUris("http://rcbb.cc");
}
5、重启服务测试
这次我们使用授权码方式进行测试,加上一些参数。
response_type=code
client_id=rcbb
redirect_uri=http://rcbb.cc
scope=all
出现登录页面,输入我们WebSecurityConfig
配置的用户信息admin/123456
。
然后就会成功,并且让我们选择是否授权。
授权成功后,会跳到对应的网址,并且url
会接上我们所需的code
。
拿到授权码后,进行获取token
的测试。我使用的是PostMan
工具进行测试。
首先需要在Authorization
上选择对应的Type
并填上AuthorizationServerConfig
中配置的client
信息。
然后Body
体以x-www-form-urlencoded
的方式,填上对应的参数。
请求的curl
curl --location --request POST 'http://127.0.0.1:8080/oauth/token' \
--header 'Authorization: Basic cmNiYjpyY2Ji' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'code=fB3uZl' \
--data-urlencode 'redirect_uri=http://rcbb.cc' \
--data-urlencode 'scope=all' \
--data-urlencode 'client_id=rcbb'
测试成功,成功获取token
。
6、配置密码模式
使用密码模式,发现并不支持。
WebSecurityConfig
补充配置认证管理器AuthenticationManager
。
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
AuthorizationServerConfig
补充配置密码模式。
@Autowired
private AuthenticationManager authenticationManager;
/**
* 配置令牌的访问端点和令牌服务
*
* @param endpoints the endpoints configurer
* @throws Exception
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
// 配置认证管理器
endpoints.authenticationManager(authenticationManager);
}
重启服务进行测试。
请求的curl
。
curl --location --request POST 'http://127.0.0.1:8080/oauth/token' \
--header 'Authorization: Basic cmNiYjpyY2Ji' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=password' \
--data-urlencode 'username=admin' \
--data-urlencode 'password=123456'
7、测试简化模式
请求参数:
response_type=token
client_id=rcbb
redirect_uri=http://rcbb.cc
scope=all
授权成功后,token
的信息直接返回在url
上了。
8、测试客户端模式
请求的curl
。
curl --location --request POST 'http://127.0.0.1:8080/oauth/token' \
--header 'Authorization: Basic cmNiYjpyY2Ji' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'client_id=rcbb' \
--data-urlencode 'client_secret=rcbb'
认证授权配置和测试
1、创建测试资源
@RestController
@RequestMapping("/user")
public class UserController {
@PostMapping
public String save() {
return "save() success";
}
@PutMapping
public String update() {
return "update() success";
}
@GetMapping
public String list() {
return "list() success";
}
}
三个请求:
- post:/user 新增用户信息
- put:/user 修改用户信息
- get:/user 获取用户信息
2、获取token
后访问资源
先获取token
。
虽然请求中携带了token
值,但是还是401 Unauthorized
。
这是为啥???
正常情况下,认证授权服务和资源服务是分开的。
正常认证授权服务是接管/oauth/token
、/oauth/token_key
、/oauth/check_token
,这三个请求,也就是这三个请求会被Spring Security OAuth2
处理。
然后我们自己写的资源应该是在资源服务上,例如/user
请求就会被Spring Security
处理。
那这种单体情况,如何处理?
3、新增资源服务配置
认证授权服务和资源服务写在一起。
ResourceServerConfig
资源服务配置。
@Configuration
@EnableResourceServer
// 开启注解鉴权
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
//配置资源服安全规则
@Override
public void configure(HttpSecurity http) throws Exception {
http
// 授权的请求
.authorizeRequests()
// 任何请求
.anyRequest()
// 需要身份认证
.authenticated()
.and().csrf().disable();
}
}
重启服务,再次请求。token
错误。
因为默认token
是存在内存中(可以配置存储在MySQL、Redis中)的,所以这里重新获取一次token
就行了。
4、给资源添加权限
@Secured("ROLE_ADMIN")
:专门用于判断是否具有角色。
@PreAuthorize("hasAuthority('user_add')")
即可判断权限,也可以判断身份,还可以使用正则判断。
如果是判断身份,那么需要填写@PreAuthorize("hasRole('ROLE_ADMIN')")
。
@RestController
@RequestMapping("/user")
public class UserController {
@PreAuthorize("hasAuthority('user_add')")
@PostMapping
public String save() {
return "save() success";
}
@PreAuthorize("hasAuthority('user_remove')")
@DeleteMapping
public String remove() {
return "remove() success";
}
@PreAuthorize("hasAuthority('user_update')")
@PutMapping
public String update() {
return "update() success";
}
@Secured("ROLE_ADMIN")
@GetMapping
public String list() {
return "list() success";
}
}
我们目前的用户信息是在WebSecurityConfig
硬编码配置的。
@Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
// 配置全局用户信息
auth.inMemoryAuthentication().withUser("admin")
.password(passwordEncoders().encode("123456"))
.authorities(AuthorityUtils.commaSeparatedStringToAuthorityList("user_add,user_update,ROLE_ADMIN"));
}
所以对应上面的资源所需权限,DELETE:/user
是无法访问的。
其他资源可正常访问。
- 0
- 0
-
分享