OAuth2.0(一)之spring-boot集成OAuth2.0[server]

现在oauth的开放授权在互联网上被广泛应用。oauth2已经被很多企业使用。

之前使用spring-mvc完成过oauth2的搭建,还是挺复杂的,本身oauth2的实现不是很难,使用spring-mvc感觉完全和oauth2的设计初衷有些背离。

现在spring-boot正在快速的崛起,使用起来也是相当的便利。本文就介绍下spring-boot集成oauth2的案例。

由于本文所涉及到的oauth2是在spring-security的基础上进行集成的,如果对security不熟悉的请参考文章 spring-boot集成spring-security

源代码地址: https://gitee.com/majinding/TM-oauth2-demo.git

数据库脚本参见 https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/test/resources/schema.sql
本文提供了一份mysql的脚本,点击下载

参考链接地址: https://projects.spring.io/spring-security-oauth/docs/oauth2.html

授权服务器配置项目搭建:

  1. 构建一个简单的maven项目
  2. 在项目中增加spring-boot和security及oauth的依赖支持
 
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>cn.majingjing.tm.oauth2</groupId>
<artifactId>tm-oauth-server</artifactId>
<version>1.0-SNAPSHOT</version>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.7.RELEASE</version>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Brixton.SR5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>


</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>


<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>

</plugins>
</build>

</project>
  1. 配置数据库和页面等配置参数
security.basic.enabled=false

server.session.timeout=300

spring.datasource.url=jdbc:mysql://127.0.0.1:3306/tm-oauth?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver


spring.datasource.max-idle=5
spring.datasource.max-wait=10000
spring.datasource.min-idle=2
spring.datasource.initial-size=3
spring.datasource.validation-query=SELECT 1
#spring.datasource.test-on-borrow=true
#spring.datasource.test-while-idle=true
spring.datasource.time-between-eviction-runs-millis=18800
spring.datasource.jdbc-interceptors=ConnectionState;SlowQueryReport(threshold=50)


spring.thymeleaf.cache=false
spring.thymeleaf.encoding=UTF-8
  1. 对AuthorizationServerConfigurerAdapter做一些自定义改造
@Configuration
public class TmAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;

@Autowired
private DataSource dataSource;

@Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
endpoints.tokenStore(tokenStore());

// 配置TokenServices参数
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setTokenStore(endpoints.getTokenStore());
tokenServices.setSupportRefreshToken(false);
tokenServices.setClientDetailsService(endpoints.getClientDetailsService());
tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());
tokenServices.setAccessTokenValiditySeconds((int) TimeUnit.DAYS.toSeconds(30)); // 30天
endpoints.tokenServices(tokenServices);

endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);// 允许get方式访问token

endpoints.pathMapping("/oauth/confirm_access", "/oauth/confirm_access_majj");

}

@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
// oauthServer.checkTokenAccess("isAuthenticated()");
oauthServer.checkTokenAccess("permitAll()");
oauthServer.allowFormAuthenticationForClients();
}

@Bean
public ClientDetailsService clientDetails() {
return new JdbcClientDetailsService(dataSource);
}

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(clientDetails());
}

}
  1. 自定义页面(这里提供了两种自定义页面的方式)
  • 授权页面
//如上的配置
endpoints.pathMapping("/oauth/confirm_access", "/oauth/confirm_access_majj");
@Controller
public class TmOauthController {
private static final Logger log = LoggerFactory.getLogger(TmOauthController.class);

@RequestMapping("/oauth/confirm_access_majj")
public String oauth(Map<String, Object> map, HttpServletRequest request,Model model) {
log.info("confirm_access_majj 重定向-model: {}", map);
log.info("confirm_access_majj 重定向-request: {}", request);
if (map.containsKey("scopes") || request.getAttribute("scopes") != null) {
@SuppressWarnings("unchecked")
Map<String, String> scopes = (Map<String, String>) (map.containsKey("scopes") ? map.get("scopes") : request
.getAttribute("scopes"));
System.out.println(scopes);
model.addAttribute("scopes", scopes);
}

return "approval";
}

}
  • 错误页面
@Controller
@SessionAttributes("authorizationRequest")
public class TmErrorController {

@RequestMapping("/oauth/error")
public String handleError(HttpServletRequest request) {
Map<String, Object> model = new HashMap<String, Object>();
Object error = request.getAttribute("error");
// The error summary may contain malicious user input,
// it needs to be escaped to prevent XSS
String errorSummary;
if (error instanceof OAuth2Exception) {
OAuth2Exception oauthError = (OAuth2Exception) error;
errorSummary = HtmlUtils.htmlEscape(oauthError.getSummary());
}
else {
errorSummary = "Unknown error";
}
model.put("errorSummary", errorSummary);
return "error";
}

}
  1. 认证提供者
@Component
public class TmAuthenticationProvider implements AuthenticationProvider {
private static final Logger log = LoggerFactory.getLogger(TmAuthenticationProvider.class);

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
log.debug("authentication.Principal:{}",authentication.getPrincipal());
return new UsernamePasswordAuthenticationToken(authentication.getPrincipal(), authentication.getCredentials(),
Collections.<GrantedAuthority>emptyList());
}

@Override
public boolean supports(Class<?> aClass) {
return true;
}
}
  1. 配置启动类(增加@EnableAuthorizationServer
@SpringBootApplication
@EnableAuthorizationServer
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}

@Autowired
private AuthenticationProvider authenticationProvider;

@Bean
public AuthenticationManager authenticationManager() {
return new ProviderManager(Arrays.asList(authenticationProvider));
}

}
  1. 启动项目,打开浏览器访问如下链接

    a。 授权
    b。 获取令牌
    c。 检查令牌

到此oauth-server已经搭建完成了。其实如果简单体验spring-boot来集成oauth2是非常简单的,本案例之所以看上去还是很复杂,是因为解释了如何使用spring提供的扩展点来完成自己的业务。

猜你喜欢

转载自blog.csdn.net/qq_33454884/article/details/88221572