Springboot Security Oauth2 第三篇:编写一个基于第二篇服务端的客户端

本文主要开发一个客户端,token认证远程关联到上一篇讲解的认证服务器中,token获取和校验都在服务器中做。
本文还会使用swagger2框架,并在swagger框架中内嵌一个登陆页面,通过登陆页面来实现token获取,这样登陆成功后,在swagger上面访问接口,都会带上登陆成功返回的token,使例子更符合正在开发场景。

1.pom.xml

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.1.2.RELEASE</version>
	<relativePath/> <!-- lookup parent from repository -->
</parent>
	
<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>

	<!-- swagger2 -->
	<dependency>
		<groupId>io.springfox</groupId>
		<artifactId>springfox-swagger2</artifactId>
		<version>2.6.1</version>
	</dependency>
	<dependency>
		<groupId>io.springfox</groupId>
		<artifactId>springfox-swagger-ui</artifactId>
		<version>2.6.1</version>
	</dependency>
	<!-- spring-security-oauth2 -->
	<dependency>
		<groupId>org.springframework.security.oauth</groupId>
		<artifactId>spring-security-oauth2</artifactId>
		<version>2.3.4.RELEASE</version>
	</dependency>
</dependencies>

2.配置资源拦截ResourceServerConfig,这里和第一篇不一样的是,配置了RemoteTokenServices,关联到远程认证服务器做token获取认证。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.RemoteTokenServices;

@Configuration
@EnableResourceServer
/**
 * 这里设置访问路径权限
 */
public class ResourceServerConfig extends ResourceServerConfigurerAdapter{

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/admin/**").hasRole("ADMIN")    //默认加上前缀ROLE_,如ROLE_ADMIN
                .antMatchers("/user/**").hasAnyRole("ADMIN","USER")
                .antMatchers("/swagger-ui.html").permitAll()	//去掉关于swagger框架的拦截
                .antMatchers("/webjars/**").permitAll() //去掉关于swagger框架的拦截
                .antMatchers("/swagger-resources/**").permitAll() //去掉关于swagger框架的拦截
                .antMatchers("/v2/**").permitAll() //去掉关于swagger框架的拦截
                .anyRequest().authenticated();
    }

    //配置远程连接授权服务器,验证token
    @Bean
    public RemoteTokenServices tokenServices(){
        RemoteTokenServices tokenServices = new RemoteTokenServices();
        //配置远程认证服务器,用于获取token地址
        tokenServices.setCheckTokenEndpointUrl("http://localhost:8888/oauth/check_token");
        //配置认证服务器的clientId和clientSecret
        tokenServices.setClientId("demoClient");
        tokenServices.setClientSecret("demoSecret");
        return tokenServices;
    }
}

3.配置swagger,这里大部分都是swagger的配置,可以自行百度了解.

import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMethod;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.builders.ResponseMessageBuilder;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spi.service.contexts.SecurityContextBuilder;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger.web.ApiKeyVehicle;
import springfox.documentation.swagger.web.SecurityConfiguration;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.nio.file.Path;
import java.util.List;

import static com.google.common.collect.Lists.newArrayList;

@Component
@EnableSwagger2
public class SwaggerConfig {


    private String securitySchemaOAuth2 = "oauth2schema";
    private AuthorizationScope authorizationScopeRead = new AuthorizationScope("read","read");
    private AuthorizationScope authorizationScopeWrite = new AuthorizationScope("write","write");
    private ApiInfo apiInfo(){
        return new ApiInfoBuilder()
                .title("swagger标题")
                .version("1.0")
                .description("write by wbb")
                .build();
    }

    @Bean
    public Docket docket(){
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.wbb.swagger2oauth2.controller"))
                .paths(PathSelectors.any())
                .build()
                .useDefaultResponseMessages(false)
                .globalResponseMessage(RequestMethod.POST, globalResponse())
                .globalResponseMessage(RequestMethod.DELETE, globalResponse())
                .globalResponseMessage(RequestMethod.PUT, globalResponse())
                .globalResponseMessage(RequestMethod.GET, globalResponse())
                .securitySchemes(newArrayList(securitySchema()))
                .securityContexts(newArrayList(securityContext()));
    }
    private SecurityContext securityContext(){
        return SecurityContext.builder()
                .securityReferences(securityReference())
                .forPaths(PathSelectors.any())
                .build();

    }
    private List<SecurityReference> securityReference(){
        AuthorizationScope[] scopes = new AuthorizationScope[2];
        scopes[0] = authorizationScopeRead;
        scopes[1] = authorizationScopeWrite;
        return newArrayList(new SecurityReference(securitySchemaOAuth2,scopes));
    }

    private List<ResponseMessage> globalResponse() {
        List<ResponseMessage> result = newArrayList();
        result.add(new ResponseMessageBuilder().code(400).message("Bad Request").build());
        result.add(new ResponseMessageBuilder().code(401).message("Unauthorized").build());
        result.add(new ResponseMessageBuilder().code(403).message("Forbidden").build());
        result.add(new ResponseMessageBuilder().code(404).message("Not Found").build());
        result.add(new ResponseMessageBuilder().code(500).message("Internal Server Error").build());
        return result;
    }

    @Bean
    SecurityConfiguration security() {
        return new SecurityConfiguration(
                "demoClient", //认证服务器clientId
                "demoSecret", //认证服务器clientSecret
                "oauth2-resource",//认证服务器resourceIds
                "swagger",
                "apiKey",
                ApiKeyVehicle.HEADER,
                "api_key",
                " " /*scope separator*/);
    }
	//token认证
    private OAuth securitySchema() {
        LoginEndpoint loginEndpoint = new LoginEndpoint("http://localhost:8888/oauth/authorize");
        GrantType grantType = new ImplicitGrant(loginEndpoint, "access_token");
        return new OAuth(securitySchemaOAuth2, newArrayList(authorizationScopeRead, authorizationScopeWrite), newArrayList(grantType));
    }

}

4.Controller


import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("")
public class MyController {

    @RequestMapping(value = "/test",method = RequestMethod.GET)
    public Object test(){
        return "test";
    }

    @RequestMapping(value = "/user",method = RequestMethod.GET)
    @PreAuthorize("hasAnyRole('ROLE_USER')")
    public Object user(){
        return "user";
    }

    @RequestMapping(value = "/user/a",method = RequestMethod.GET)
    public Object user2(){
        return "user";
    }

    @PreAuthorize("hasAnyRole('ROLE_ADMIN')")
    @RequestMapping(value = "/admin",method = RequestMethod.GET)
    public Object admin(){
        return "admin";
    }

    @RequestMapping(value = "/admin/b",method = RequestMethod.GET)
    public Object admin2(){
        return "admin";
    }

5.这样整个项目就写完了,直接启动,不过在启动前需要先启动认证服务器(在上一篇写过)。
启动后,打开http://localhost:9999/swagger-ui.html#/,会出现一个swagger页面
在这里插入图片描述
随便点开一个url访问,会报没有认证的错误,跟之前我们用postman访问接口一样
在这里插入图片描述
接着,点击右上角的Authorize按钮,会弹出一个窗口
在这里插入图片描述
选择多选框,再点击Authorize按钮,会跳转到一个授权页面
在这里插入图片描述
再点击Authorize,会跳转到登陆页面,我这边登陆页面比较简单,如果需要的话,可以自行加工。直接输入账号密码登陆,这个登陆账号密码和第二篇用postman访问登陆一样。
在这里插入图片描述
点击登陆,登陆后,会返回到swagger页面,蓝色表示已登陆,红色是未登录。
登陆的原因在于第二篇yml配置中的spring.security.oauth2.client.redirectUris参数,登陆成功后重定向到客户端的swagger页面,该参数可以配置多个客户端swagger地址,上一篇中就配置了两个,大家可以修改客户端地址,多启动几个客户端,测试一下是不是这个样子
在这里插入图片描述
再接着访问第一个admin接口,会报无权限,跟上一篇postman演示一样
在这里插入图片描述
接着再访问user接口,访问成功
在这里插入图片描述

演示到这里就结束了。这个客户端,是不是很简单,本文这里集成了swagger,如果不需要,去掉swagger的配置就好了,通过接口获取token,然后再带上token访问接口,就和之前用postman演示一样。

讲到这里,本篇文章到此也就结束了,如果文章中有问题,或者有一些不够严谨完善的地方,希望大家体谅体谅。欢迎大家留言,交流交流。

最好附上项目github地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值