Spring Security OAuth2基于JWT认证授权

OAuth2是一种授权方法,用于通过HTTP协议提供对受保护资源的访问。首先,OAuth2使第三方应用程序能够获得对HTTP服务的有限访问权限,然后通过资源所有者和HTTP服务之间的批准交互来让第三方应用程序代表资源所有者获取访问权限。

OAuth包括以下角色

  • 资源拥有者 - 应用程序的用户。
  • 客户端 - ,需要通过资源拥有者的授权去请求资源服务器的资源的应用程序,如Android客户端、Web客户端(浏 览器端)、微信客户端等
  • 资源服务器 - 存储用户数据和http服务,可以将用户数据返回给经过身份验证的客户端。
  • 授权服务器 - 负责验证用户的身份并提供授权令牌。资源服务器接受此令牌并验证您的身份。

oauth2认证流程

创建oauth_client_details表

-- ------------------------------ Table structure for oauth_client_details-- ----------------------------DROP TABLE IF EXISTS `oauth_client_details`;CREATE TABLE `oauth_client_details` (  `client_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '客户端标 识',  `resource_ids` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '接入资源列表',  `client_secret` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '客户端秘钥',  `scope` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,  `authorized_grant_types` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,  `web_server_redirect_uri` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,  `authorities` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,  `access_token_validity` int DEFAULT NULL,  `refresh_token_validity` int DEFAULT NULL,  `additional_information` longtext CHARACTER SET utf8 COLLATE utf8_general_ci,  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,  `archived` tinyint DEFAULT NULL,  `trusted` tinyint DEFAULT NULL,  `autoapprove` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,  PRIMARY KEY (`client_id`) USING BTREE) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 ROW_FORMAT=DYNAMIC COMMENT='接入客户端信息';

创建oauth_code表

-- ------------------------------ Table structure for oauth_code-- ----------------------------DROP TABLE IF EXISTS `oauth_code`;CREATE TABLE `oauth_code` (  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,  `code` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,  `authentication` blob,  KEY `code_index` (`code`) USING BTREE) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 ROW_FORMAT=COMPACT;

工程目录

创建一个父maven工程,并引入依赖

<?xml version="1.0" encoding="UTF-8"?>    4.0.0    tjw    cloud-oauth2    pom    1.0-SNAPSHOT            auth-server        order-a                org.springframework.boot        spring-boot-starter-parent        2.2.4.RELEASE                         1.8        Hoxton.SR1                                    org.thymeleaf.extras            thymeleaf-extras-springsecurity5            3.0.4.RELEASE                            org.springframework.boot            spring-boot-starter-jdbc                            mysql            mysql-connector-java            runtime                            org.mybatis.spring.boot            mybatis-spring-boot-starter            2.1.1                            org.springframework.boot            spring-boot-starter-thymeleaf                            org.springframework.boot            spring-boot-starter-web                            org.springframework.cloud            spring-cloud-starter-oauth2                            org.projectlombok            lombok            true                            org.springframework.boot            spring-boot-starter-test            test                                                org.junit.vintage                    junit-vintage-engine                                                                                org.springframework.cloud                spring-cloud-dependencies                ${spring-cloud.version}                pom                import                        

创建授权服务器

application.yml

server:  port: 8081  servlet:    context-path: /authspring:  datasource:    driver-class-name: com.mysql.cj.jdbc.Driver    url: jdbc:mysql://127.0.0.1:3305/item?serverTimezone=UTC    username: root    password: 123456  main:    #当遇到同样名字的bean时,是否允许覆盖注册    allow-bean-definition-overriding: true

授权服务配置类

@Configuration@EnableAuthorizationServerpublic class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {     @Autowired    ClientDetailsService clientDetailsService;    @Autowired    AuthenticationManager authenticationManager;    @Autowired    AuthorizationCodeServices authorizationCodeServices;    @Autowired    TokenStore tokenStore;    @Autowired    JwtAccessTokenConverter jwtAccessTokenConverter;    @Autowired    PasswordEncoder passwordEncoder;//    @Bean//    public AuthorizationCodeServices authorizationCodeServices() { //        return new InMemoryAuthorizationCodeServices();//    }//基于数据库的授权码服务    @Bean    public AuthorizationCodeServices authorizationCodeServices(DataSource dataSource) {         return new JdbcAuthorizationCodeServices(dataSource);    }//localhost:8081/oauth/authorize?client_id=c1&response_type=code&scope=all&redirect_uri=http://www.baidu.com    // 令牌管理服务    @Bean    public AuthorizationServerTokenServices tokenService() {          DefaultTokenServices service=new DefaultTokenServices();         service.setClientDetailsService(clientDetailsService);         service.setSupportRefreshToken(true);         service.setTokenStore(tokenStore);        // jwt令牌配置        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();        tokenEnhancerChain.setTokenEnhancers(Arrays.asList(jwtAccessTokenConverter));        service.setTokenEnhancer(tokenEnhancerChain);        service.setAccessTokenValiditySeconds(7200); // 令牌默认有效期2小时         service.setRefreshTokenValiditySeconds(259200); // 刷新令牌默认有效期3天 return service;         return service;    }    @Override    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {         super.configure(security);         security.tokenKeyAccess("permitAll()")                 .checkTokenAccess("permitAll()")                 .allowFormAuthenticationForClients();    }    // 重写ClientDetailsService,将客户端的信息存储到数据库    @Bean    public ClientDetailsService clientDetailsService(DataSource dataSource){         JdbcClientDetailsService jdbcClientDetailsService = new JdbcClientDetailsService(dataSource);        jdbcClientDetailsService.setPasswordEncoder(passwordEncoder);        return jdbcClientDetailsService;    }    @Override    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {         clients.withClientDetails(clientDetailsService);     //基于内存//        clients.inMemory()//                .withClient("c1")//client_id//                .secret(new BCryptPasswordEncoder().encode("secret"))//                .resourceIds("res1")//                .authorizedGrantTypes("authorization_code","password","client_credentials","implicit","refresh_token")//该client允许的授权类型authorization_code,password,refresh_token,implicit,client_credentials//                .scopes("all")//允许的授权范围//                .autoApprove(false)//                //加上验证回调地址//                .redirectUris("http://www.baidu.com");    }    @Override    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {                 endpoints.authenticationManager(authenticationManager)            .authorizationCodeServices(authorizationCodeServices)             .tokenServices(tokenService())            .allowedTokenEndpointRequestMethods(HttpMethod.POST);    }}

属性

clientId - (必需)客户端ID。

secret - (可信客户端所需)客户端密钥(可选)。

scope - 客户受限的范围。如果范围未定义或为空(默认值),则客户端不受范围限制。

authorizedGrantTypes - 授权客户端使用的授权类型。默认值为空。

authorities - 授予客户的权限(常规Spring Security权限)。

redirectUris - 将用户代理重定向到客户端的重定向端点。它必须是绝对URL。

创建资源服务器

@Configuration@EnableResourceServer@EnableGlobalMethodSecurity(prePostEnabled = true)public class ResourceServerConfig extends ResourceServerConfigurerAdapter {     public static final String RESOURCE_ID = "res1";    @Autowired    TokenStore tokenStore;    public ResourceServerTokenServices tokenServices(){         RemoteTokenServices services = new RemoteTokenServices();        services.setCheckTokenEndpointUrl("http://localhost:8081/auth/oauth/check_token");        services.setClientId("c1");        services.setClientSecret("secret");        return services;    }    @Override    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {         resources.resourceId(RESOURCE_ID)                // 使用jwt令牌进行校验                .tokenStore(tokenStore)                //验证令牌服务//                .tokenServices(tokenServices())                .stateless(true);    }    @Override    public void configure(HttpSecurity http) throws Exception {         http.authorizeRequests()                .antMatchers("/**")//                .hasAnyAuthority("all","ROLE_ADMIN")                .access("#oauth2.hasScope('ROLE_ADMIN')")                .and().csrf().disable()                .sessionManagement()                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);    }}

资源

@RestControllerpublic class OrderController {     @GetMapping("/r1")    @PreAuthorize("hasAnyAuthority('p1')")    public String r1(){         return "资源1";    }}

测试

浏览器输入

localhost:8081/auth/oauth/authorize?client_id=c1&response_type=code&scope=ROLE_ADMIN&redirect_uri=http://www.baidu.com

注意这里的client_id、scope、redirect_uri 的值来自数据库

过浏览器访问上面的URL地址,它将展现一个登录页面。提供用户名和密码。

点击authorize

这样就拿到了授权码,使用授权码来生成JWT token

使用token,来访问资源

发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章