spring|spring boot security自定义配置授权服务器实现Oauth2授权(支持密码和授权码两种模式)
1、application.yml
server:
port: 8888security:
oauth2:
client:
client-id: test_client_id
client-secret: test_client_secret
scope: read,write
auto-approve-scopes: '.*'logging:
level:
org.springframework.security: info
2、pom.xml
org.springframework.boot
spring-boot-starter-actuator
org.springframework.boot
spring-boot-starter-security
org.springframework.boot
spring-boot-starter-web
org.springframework.security.oauth
spring-security-oauth2
3、自定义授权服务器配置CustomAuthorizationServerConfiguration.java
package com.zmx.springcloud.config.authorization_server;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
/**
* 自定义配置授权服务器
* 配置授权的相关信息,配置的核心都在这里 在这里进行配置客户端,配置token存储方式等
* @author zhangwenchao
*
*/
@Configuration
//认证服务器
@EnableAuthorizationServer
public class CustomAuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter implements EnvironmentAware {
private Logger logger = LoggerFactory.getLogger(CustomAuthorizationServerConfiguration.class);
private static final String ENV_OAUTH = "security.oauth2.client.";
private static final String PROP_CLIENTID = "client-id";
private static final String PROP_SECRET = "client-secret";
/**
* 使用EnvironmentAware的setEnvironment方法初始化
*/
private RelaxedPropertyResolver propertyResolver;
/**
* 认证管理器
*/
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
/**
* UserDetailsService
*/
@Autowired
private UserDetailsService userDetailsService;
/*
@Autowired
private DataSource dataSource;
@Bean
public TokenStore tokenStoreForJDBC(){
//这个是基于JDBC的实现tokenStore,令牌(Access Token)会保存到数据库
return new JdbcTokenStore(dataSource);
}
*/@Bean("tokenStore")
public TokenStore tokenStore() {
//使用内存的tokenStore,令牌(Access Token)会保存到内存
return new InMemoryTokenStore();
}@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
// endpoints.tokenStore(tokenStoreForJDBC()).authenticationManager(authenticationManager).userDetailsService(customUserDetailsService);
//配置userDetailsService这样每次认证的时候会去检验用户是否锁定,有效等
endpoints.tokenStore(tokenStore()).authenticationManager(authenticationManager).userDetailsService(userDetailsService);
}/**
* 声明ClientDetailService--验证客户端id与secret
*/
/*
@Bean
public ClientDetailsServicegetClientDetails() {
return new ClientDetailsService() {@Override
public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {ClientDetails clientDetails = new BaseClientDetails();
return clientDetails;
}
};
}
*/@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {logger.info("===============配置授权服务器开始...=========");
//clients.withClientDetails(getClientDetails());
//数据库验证方式/**
* 配置客户端clientid secret等信息
*/
clients.inMemory() // 使用in-memory存储
.withClient(propertyResolver.getProperty(PROP_CLIENTID))//client_id用来标识客户的Id
.scopes("read", "write") //允许授权范围--这一项用于服务提供商区分提供哪些服务数据
//.authorities("ROLE_ADMIN","ROLE_USER")//客户端可以使用的权限
.authorizedGrantTypes("authorization_code","password", "refresh_token")//允许授权类型
.secret(propertyResolver.getProperty(PROP_SECRET))//secret客户端安全码
.accessTokenValiditySeconds(10000) //token过期时间
.refreshTokenValiditySeconds(100000);
//refresh过期时间
logger.info("===============配置授权服务器完成=========");
}@Override
public void setEnvironment(Environment environment) {
//获取到前缀是"authentication.oauth." 的属性列表值.
this.propertyResolver = new RelaxedPropertyResolver(environment, ENV_OAUTH);
}}
4、自定义登录验证,CustomUserDetailsService.java
package com.zmx.springcloud.config.authorization_server;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import org.springframework.context.annotation.Primary;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import com.zmx.springcloud.entity.MyUserDetails;
import com.zmx.springcloud.entity.User;
@Primary
@Service("userDetailsService")
public class CustomUserDetailsService implements UserDetailsService{
//@Autowired//业务服务类
//private UserService userService;
private final static Set users = new HashSet<>();
static {
users.add(new User(1, "test-user1", "123456"));
users.add(new User(2, "test-user2", "123456"));
users.add(new User(3, "test-user3", "123456"));
users.add(new User(4, "test-user4", "123456"));
}/**
* spring会将MyUserDetails中的密码与session中的密码比较,否是验证通过
*/
@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException { //User对应数据库中的用户表,是最终存储用户和密码的表
//User user = userService.findByName(userName);
//if (user == null) {
// throw new UsernameNotFoundException("UserName " + userName + " not found");
//}//grantedAuthorities对应数据库中权限的表
Collection grantedAuthorities = new ArrayList();
grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_USER"));
Optional user = users.stream()
.filter((u) -> u.getUsername().equals(userName))
.findFirst();
if (user.isPresent()){
return new MyUserDetails(user.get(),grantedAuthorities);
}else{
throw new UsernameNotFoundException("there's no user founded!");
} }
}
5、测试一个需授权的资源并测试
package com.zmx.springcloud.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.zmx.springcloud.entity.MyUserDetails;
import com.zmx.springcloud.entity.User;
@RestController
@RequestMapping("/secure")
public class UserController {@Autowired
private TokenStore tokenStore;
@PostMapping("/user")
public String user(@RequestHeader("Authorization") String auth) { //需要提供访问的token才能访问,资源服务也需要验证token是否有效
String token = auth.split(" ")[1];
//获取token(验证)
MyUserDetails userDetails = (MyUserDetails) tokenStore.readAuthentication(token).getPrincipal();
User user = userDetails.getUser();
return user.getUsername() + ":" + user.getPassword();
}}
6、测试密码模式
6.1获取token:访问:http://localhost:8888/oauth/token,需要client-id与secret生成header(base64编码)
文章图片
文章图片
文章图片
6.2使用token访问授权资源:
文章图片
7、使用授权码模式访问受限资源:
7.1 获取code,访问:
http://localhost:8888/oauth/authorize?
response_type=code&client_id=test_client_id&redirect_uri=http://www.baidu.com&scope=read write
文章图片
会跳转到授权页面,收入用户名和密码:
文章图片
登录成功后,跳转到下面页面:
文章图片
同意并授权后跳转到redirect-uri页面并带上code,如下页面从而能获取到code:
文章图片
7.2根据code获取token:
文章图片
同样的也需要client-id与secret组成Authorization头部信息:
7.3使用token访问授权资源
文章图片
至此,两种模式均已验证完毕!
【spring|spring boot security自定义配置授权服务器实现Oauth2授权(支持密码和授权码两种模式)】
推荐阅读
- Spring|SpringSecurity + JWT自定义授权
- springboot 集成 spring security 自定义登录
- springsecurity|SpringSecurity自定义登录界面
- SpringBoot|SpringBoot-数据层操作
- spring|springboot+mybais+mabatisplus(swagger)实现增删改查接口
- springboot|springboot两种配置文件bootstrap.properties和application.properties的区别
- SpringBoot|SpringBoot读取配置文件到实体类和静态变量
- spring|Spring Cloud微服务治理框架深度解析
- #|【微服务】一文读懂网关概念+Nginx正反向代理+负载均衡+Spring Cloud Gateway(多栗子)