1.单点登录简介
- 单点登录(Single Sign On)指的是当有多个系统需要登录时,用户只需登录一个系统,就可以访问其他需要登录的系统而无需登录。
2.创建client模块
– 这里我们创建一个security-clientt服务作为需要登录的客户端服务,使用上一节中的oauth2-jwt-server服务作为认证服务,当我们在security-server服务上登录以后,就可以直接访问security-client需要登录的接口,来演示下单点登录功能。
2.1 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>
2.2 application配置
server:
port: 8777
servlet:
session:
cookie:
name: OAUTH2-CLIENT-SESSIONID #防止Cookie冲突,冲突会导致登录验证不通过
# 这里填127... 后面测试时浏览器也输入127...
oauth2-server-url: http://127.0.0.1:8666
spring:
application:
name: security-client
security:
oauth2:
client:
client-id: admin
client-secret: admin123456
user-authorization-uri: ${oauth2-server-url}/oauth/authorize
access-token-uri: ${oauth2-server-url}/oauth/token
id: admin1
grant-type: password
scope: all
resource:
token-info-uri: ${oauth2-server-url}/oauth/check_token
# jwt 的配置
jwt:
key-uri: ${oauth2-server-url}/oauth/token_key
# user-info-uri 与 token-info-uri
#作用:二者皆是为了check token user-info-uri: http://localhost:9005/user
2.3 @EnableOAuth2Sso启用单点登录功能
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
@EnableOAuth2Sso
@SpringBootApplication
public class SecurityClientApplication {
public static void main(String[] args) {
SpringApplication.run(SecurityClientApplication.class, args);
}
}
2.4 添加接口用于获取当前登录用户信息
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController @RequestMapping("/user")
public class UserController {
@GetMapping("/getCurrentUser")
// @PreAuthorize("hasRole('admin')")
// Authentication 别引错,不然收不到值
public WebResponse getCurrentUser(Authentication authentication) {
return new WebResponse("Y",authentication,"返回");
}
}
3.修改认证服务器
owner:
redirectUri: http://127.0.0.1:8777/login
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private AuthenticationManager authenticationManager;
@Value("${owner.redirectUri}")
private String redirectUris;
// 改为JWT
@Resource(name = "jwtTokenStore")
private TokenStore tokenStore;
@Autowired
private JwtAccessTokenConverter jwtAccessTokenConverter;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("admin")//配置client_id
.secret(passwordEncoder.encode("admin123456"))//配置client_secret
.accessTokenValiditySeconds(3600)//配置访问token的有效期
.refreshTokenValiditySeconds(8640)//配置刷新token的有效期
.redirectUris(redirectUris)//配置redirect_uri,用于授权成功后跳转 单点登录时配置
.scopes("all") // 配置申请的权限范围,授权页面会显示
//.autoApprove(true) //自动授权配置
.authorizedGrantTypes("authorization_code","password","refresh_token");//配置grant_type,表示授权类型
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) {
// 获取密钥需要身份认证,使用单点登录时必须配置, 默认为全部拒绝 permitAll() isAuthenticated() denyAll()
security.tokenKeyAccess("isAuthenticated()");//.checkTokenAccess("isAuthenticated()");
}
// 使用密码模式需要配置
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager)
// 设置为redis 配置令牌存储策略
.tokenStore(tokenStore)
// 转为jwt格式
.accessTokenConverter(jwtAccessTokenConverter);
}
}
4.测试
4.1 网页版
- 访问客户端需要授权的接口http://127.0.0.1:8777/user/getCurrentUser会跳转到授权服务的登录界面;
- 进行授权
- 授权后会跳转到原来需要权限的接口地址,展示登录用户信息
4.2 Postman来演示
- 这里我们使用Postman来演示下如何使用正确的方式调用需要登录的客户端接口。
这里开启自动授权,AuthorizationServerConfig 中的.autoApprove(true) //自动授权配置
- 访问客户端需要登录的接口:http://127.0.0.1:8777/user/getCurrentUser
- 使用Oauth2认证方式获取访问令牌:
- 点击request_token,t跳到登录页
- 登录完成获取到令牌
- 使用这个token,然后发送请求
- 得到返回
5.security-client权限校验
5.1 开启基于方法的权限校验
@Configuration
// @EnableGlobalMethodSecurity(prePostEnabled = true) 开启后,Spring Security 的 @PreAuthorize,@PostAuthorize 注解才可以使用。
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Order(101)
public class SecurityConfig
extends WebSecurityConfigurerAdapter {
/*@Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
// 基于token,所以不需要session
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.anyRequest().authenticated();
}*/
}
5.2 添加需要admin权限的接口
@RestController @RequestMapping("/user")
public class UserController {
@GetMapping("/getCurrentUser")
// @PreAuthorize("hasRole('admin')")
// Authentication 别引错,不然收不到值
public WebResponse getCurrentUser(Authentication authentication) {
return new WebResponse("Y",authentication,"返回");
}
@GetMapping("/adminAuth")
@PreAuthorize("hasAuthority('admin')")
public WebResponse adminAuth() {
return new WebResponse("y","可以的");
}
}
5.3 测试
- 访问需要admin权限的接口:http://127.0.0.1:8777/user/adminAuth
- 使用admin账户
- 使用user 账户