文章目录
摘要
单点登录简介
创建oauth2-client模块
修改授权服务器配置
网页单点登录演示
调用接口单点登录演示
oauth2-client添加权限校验
使用到的模块
项目源码地址
项目使用的Spring Cloud为Hoxton版本,Spring Boot为2.2.2.RELEASE版本
摘要
Spring Cloud Security 为构建安全的SpringBoot应用提供了一系列解决方案,结合Oauth2可以实现单点登录功能,本文将对其单点登录用法进行详细介绍。
单点登录简介
单点登录(Single Sign On)指的是当有多个系统需要登录时,用户只需登录一个系统,就可以访问其他需要登录的系统而无需登录。
创建oauth2-client模块
这里我们创建一个oauth2-client服务作为需要登录的客户端服务,使用上一节中的oauth2-jwt-server服务作为授权服务,当我们在oauth2-jwt-server服务上登录以后,就可以直接访问oauth2-client需要登录的接口,来演示下单点登录功能。
在pom.xml中添加相关依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency><dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-oauth2</artifactId></dependency><dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-security</artifactId></dependency>
在application.yml中进行配置:
server: port: 9501 servlet: session: cookie: # 防止cookie冲突,冲突会导致登录验证不通过 name: OAUTH2-CLIENT-SESSIONIDoauth2-service-url: http://localhost:9401spring: application: name: oauth2-clientsecurity: # 与oauth2-server对应的配置 oauth2: client: client-id: admin client-secret: admin123456 user-authorization-uri: ${oauth2-service-url}/oauth/authorize access-token-uri: ${oauth2-service-url}/oauth/token resource: jwt: key-uri: ${oauth2-service-url}/oauth/token_key
在启动类上添加@EnableOAuth2Sso注解来启用单点登录功能:
@EnableOAuth2Sso@SpringBootApplicationpublic class Oauth2ClientApplication { public static void main(String[] args) { SpringApplication.run(Oauth2ClientApplication.class, args); }}
添加接口用于获取当前登录用户信息:
@RestController@RequestMapping("/user")public class UserController { @GetMapping("/getCurrentUser") public Object getCurrentUser(Authentication authentication) { return authentication; }}修改授权服务器配置
修改oauth2-jwt-server模块中的AuthorizationServerConfig类,将绑定的跳转路径为http://localhost:9501/login,并添加获取秘钥时的身份认证。
@Configuration@EnableAuthorizationServerpublic class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { //以上省略一堆代码... @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() // 配置client_id .withClient("admin") // 配置client_secret .secret(passwordEncoder.encode("admin123456")) // 配置访问token的有效期 .accessTokenValiditySeconds(3600) // 配置刷新token的有效期 .refreshTokenValiditySeconds(864000) // 配置redirect_uri,用于授权成功后的跳转 // .redirectUris("") // 单点登录时配置 .redirectUris("http://localhost:9501/login") // 自动授权配置 // .autoApprove(true) // 配置申请的权限范围 .scopes("all") // 配置grant_type,表示授权类型 .authorizedGrantTypes("authorization_code", "password", "refresh_token"); } @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { // 获取密钥需要身份认证,使用单点登录时必须配置 security.tokenKeyAccess("isAuthenticated()"); }}网页单点登录演示
启动oauth2-client服务和oauth2-jwt-server服务;
访问客户端需要授权的接口http://localhost:9501/user/getCurrentUser会跳转到授权服务的登录界面;
进行登录操作后跳转到授权页面;
授权后会跳转到原来需要权限的接口地址,展示登录用户信息;
如果需要跳过授权操作进行自动授权可以添加autoApprove(true)配置:
@Configuration@EnableAuthorizationServerpublic class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { //以上省略一堆代码... @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() // 配置client_id .withClient("admin") // 配置client_secret .secret(passwordEncoder.encode("admin123456")) // 配置访问token的有效期 .accessTokenValiditySeconds(3600) // 配置刷新token的有效期 .refreshTokenValiditySeconds(864000) // 配置redirect_uri,用于授权成功后的跳转 // .redirectUris("") // 单点登录时配置 .redirectUris("http://localhost:9501/login") // 自动授权配置 .autoApprove(true) // 配置申请的权限范围 .scopes("all") // 配置grant_type,表示授权类型 .authorizedGrantTypes("authorization_code", "password", "refresh_token"); }}调用接口单点登录演示
这里我们使用Postman来演示下如何使用正确的方式调用需要登录的客户端接口。
访问客户端需要登录的接口:http://localhost:9501/user/getCurrentUser
使用Oauth2认证方式获取访问令牌:
输入获取访问令牌的相关信息,点击请求令牌:
此时会跳转到授权服务器进行登录操作:
登录成功后使用获取到的令牌:
最后请求接口可以获取到如下信息:
{ "authorities": [{ "authority": "admin" }], "details": { "remoteAddress": "0:0:0:0:0:0:0:1", "sessionId": "6F5A553BB678C7272145FF9FF2A5D8F4", "tokenValue": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJqb3Vyd29uIiwic2NvcGUiOlsiYWxsIl0sImV4cCI6MTU3NzY4OTc2NiwiYXV0aG9yaXRpZXMiOlsiYWRtaW4iXSwianRpIjoiZjAwYjVkMGUtNjFkYi00YjBmLTkyNTMtOWQxZDYwOWM4ZWZmIiwiY2xpZW50X2lkIjoiYWRtaW4iLCJlbmhhbmNlIjoiZW5oYW5jZSBpbmZvIn0.zdgFTWJt3DnAsjpQRU6rNA_iM7gVHX7E9bCyF73MOSM", "tokenType": "bearer", "decodedDetails": null }, "authenticated": true, "userAuthentication": { "authorities": [{ "authority": "admin" }], "details": null, "authenticated": true, "principal": "jourwon", "credentials": "N/A", "name": "jourwon" }, "clientOnly": false, "oauth2Request": { "clientId": "admin", "scope": ["all"], "requestParameters": { "client_id": "admin" }, "resourceIds": [], "authorities": [], "approved": true, "refresh": false, "redirectUri": null, "responseTypes": [], "extensions": {}, "grantType": null, "refreshTokenRequest": null }, "principal": "jourwon", "credentials": "", "name": "jourwon"}oauth2-client添加权限校验
添加配置开启基于方法的权限校验:
@Configuration@EnableGlobalMethodSecurity(prePostEnabled = true)@Order(101)public class SecurityConfig extends WebSecurityConfigurerAdapter {}
在UserController中添加需要admin权限的接口:
@RestController@RequestMapping("/user")public class UserController { @PreAuthorize("hasAuthority("admin")") @GetMapping("/auth/admin") public Object adminAuth() { return "Has admin auth!"; }}
访问需要admin权限的接口:http://localhost:9501/user/auth/admin
使用没有admin权限的帐号,比如andy:123456获取令牌后访问该接口,会发现没有权限访问。
使用到的模块
springcloud-learning├── oauth2-jwt-server -- 使用jwt的oauth2认证测试服务└── oauth2-client -- 单点登录的oauth2客户端服务项目源码地址
GitHub项目源码地址