SpringBoot+Security+Oauth2+Jwt+数据库

1、Oauth2 相关的数据库

DROP TABLE IF EXISTS `oauth_access_token`;
CREATE TABLE `oauth_access_token` (
  `token_id` varchar(255) DEFAULT NULL,
  `token` blob,
  `authentication_id` varchar(255) DEFAULT NULL,
  `user_name` varchar(255) DEFAULT NULL,
  `client_id` varchar(255) DEFAULT NULL,
  `authentication` blob,
  `refresh_token` varchar(255) DEFAULT NULL,
  KEY `token_id_index` (`token_id`),
  KEY `authentication_id_index` (`authentication_id`),
  KEY `user_name_index` (`user_name`),
  KEY `client_id_index` (`client_id`),
  KEY `refresh_token_index` (`refresh_token`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `oauth_client_details`;
CREATE TABLE `oauth_client_details` (
  `client_id` varchar(255) NOT NULL,
  `client_secret` varchar(255) DEFAULT NULL,
  `resource_ids` varchar(255) DEFAULT NULL,
  `scope` varchar(255) DEFAULT NULL,
  `authorized_grant_types` varchar(255) DEFAULT NULL,
  `web_server_redirect_uri` varchar(255) DEFAULT NULL,
  `authorities` varchar(255) DEFAULT NULL,
  `access_token_validity` int(11) DEFAULT NULL,
  `refresh_token_validity` int(11) DEFAULT NULL,
  `additional_information` text,
  `autoapprove` varchar(255) DEFAULT 'false',
  PRIMARY KEY (`client_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert  into `oauth_client_details`(`client_id`,`client_secret`,`resource_ids`,`scope`,`authorized_grant_types`,`web_server_redirect_uri`,`authorities`,`access_token_validity`,`refresh_token_validity`,`additional_information`,`autoapprove`) values ('client1','$2a$10$cYYV9YSQXQPcLT.sPlgZQeAe7N7k50ktWJBAm.jNLeiPrtJLYYVRC','my-resource','access_token','client_credentials,refresh_token',NULL,'USER',43200,43200,NULL,'false'),('client2','$2a$10$dXV2c1BDGI7ALdQa/lR.hOxCrW5OD.hDM6NXDj0KSWaP5wd9DH1MS','my-resource','access_token','password,refresh_token',NULL,'USER',43200,43200,NULL,'false');

DROP TABLE IF EXISTS `oauth_code`;
CREATE TABLE `oauth_code` (
  `code` varchar(255) DEFAULT NULL,
  `authentication` blob,
  KEY `code_index` (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `oauth_refresh_token`;
CREATE TABLE `oauth_refresh_token` (
  `token_id` varchar(255) DEFAULT NULL,
  `token` blob,
  `authentication` blob,
  KEY `token_id_index` (`token_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

3、yml配置

server:
  port: 9101
  tomcat:
    uri-encoding: UTF-8
    max-threads: 1000
    min-spare-threads: 30

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/oauth2?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2B8
    username: root
    password: root
  redis:
    host: redis-host
    port: 6379

2、依赖

 <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.11.RELEASE</version>
    </parent>

    <dependencies>

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

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

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>

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

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

        <dependency>
            <groupId>org.springframework.security.oauth.boot</groupId>
            <artifactId>spring-security-oauth2-autoconfigure</artifactId>
            <version>2.1.3.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-redis</artifactId>
            <version>1.4.4.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.4</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

    </dependencies>

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

4、实体类

/**
 * @author zhe.xiao
 * @date 2021-03-27 13:09
 * @description
 */
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class MyUser {
    private Long id;
    private String username;
    private String password;
    private Integer phone;
    private Boolean active;
}

5、controller接口测试

@RestController
@RequestMapping("/goods")
public class GoodsController {

    @GetMapping("/list")
    public String list(){
        return "商品列表";
    }



    @GetMapping("/add")
    public String add(){
        return "添加商品成功";
    }


    @GetMapping("/update")
    public String update(){
        return "修改商品成功";
    }


    @GetMapping("/delete")
    public String delete(){
        return "删除商品成功";
    }
}

6、实现UserDetailsService接口


@Service
public class UserService implements UserDetailsService {

    @Autowired
    PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        MyUser myUser = getUser(username);

        return new User(
                myUser.getUsername(),
                myUser.getPassword(),
                myUser.getActive(),
                true,
                true,
                true,
                getAuthority(myUser)
        );
    }

    /**
     * 模拟 从数据库读取的用户
     *
     * @param username
     * @return
     */
    private MyUser getUser(String username) {
        return new MyUser()
                .setUsername(username)
                .setId(1L)
                .setPassword(passwordEncoder.encode("123"))
                .setActive(true);
    }

    /**
     * 模拟 读取到的用户权限
     *
     * @param myUser
     * @return
     */
    private List<GrantedAuthority> getAuthority(MyUser myUser) {
        List<GrantedAuthority> list = new ArrayList<>();
        list.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
        return list;
    }
}


7、secrity配置

/**
 * @author zhe.xiao
 * @date 2021-03-26 15:46
 * @description
 * OAUTH2 第一步配置 web
 */
@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    PasswordEncoder passwordEncoder;

    @Autowired
    UserService userDetailsService;

    /**
     * 认证管理器
     * OAUTH2 认证服务器会使用这个
     * @return
     * @throws Exception
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    /**
     * 用户验证
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }

    /**
     * HTTP请求权限
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/goods/list").permitAll()
                .antMatchers("/goods/add").permitAll()
                .antMatchers("/goods/update").permitAll()
                .antMatchers("/goods/delete").permitAll()
                .antMatchers("/oauth/**").permitAll()
                .antMatchers("/api/**").authenticated();
    }
}

8、Oauth2认证服务器配置

/**
 * @author zhe.xiao
 * @date 2021-03-26 15:23
 * @description Oauth2 第三步 配置认证服务器
 */
@EnableAuthorizationServer
@Configuration
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    private static final String JWT_SINGING_KEY = "my-sign-key-xxxxxx";

    @Autowired
    PasswordEncoder passwordEncoder;

    @Autowired
    DataSource dataSource;

    @Autowired
    AuthenticationManager authenticationManager;

    @Autowired
    UserService userDetailsService;

    /**
     * 设置第三方client相关的数据信息
     * @param clients
     * @throws Exception
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.withClientDetails(clientDetailsService());
    }

    /**
     * 设定一些与认证相关的配置
     *
     * @param endpoints
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(tokenStore()) //配置token存储信息
                .accessTokenConverter(jwtAccessTokenConverter()) //配置jwt
                .authenticationManager(authenticationManager) //配置认证
                .userDetailsService(userDetailsService) //配置用户信息
                .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST); //支持OAUTH相关接口以GET和POST方法请求
    }

    /**
     * 一些服务器配置
     *
     * @param oauthServer
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        oauthServer.allowFormAuthenticationForClients() //支持请求数据通过表单的形式发送
                .tokenKeyAccess("permitAll()")
                .checkTokenAccess("permitAll()");
    }

    /**
     * 数据库存储token信息
     * 主要表:oauth_access_token、oauth_refresh_token
     *
     * @return
     */
    @Bean
    public TokenStore tokenStore() {
        return new JdbcTokenStore(dataSource);
    }

    /**
     * 数据库读取client的相关数据
     * 主要表:oauth_client_details
     *
     * 注意:这里需要重命名bean name,否则会提示 clientDetailsService 无法被override
     * @return
     */
    @Bean(name = "oauthClientDetailsService")
    public JdbcClientDetailsService clientDetailsService() {
        return new JdbcClientDetailsService(dataSource);
    }

    /**
     * 生成JWT
     *
     * @return
     */
    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey(JWT_SINGING_KEY);
        return converter;
    }
}

9、Oauth2资源服务器配置

/**
 * @author zhe.xiao
 * @date 2021-03-26 15:35
 * @description
 * Oauth2 第二步 配置资源服务器
 */
@EnableResourceServer
@Configuration
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
    public static final String RESOURCE_NAME = "my-resource";

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        //只有基于token的认证才可以访问这些资源
        resources.resourceId(RESOURCE_NAME).stateless(true);
    }
}

10、测试结果:

10.1、client_credentials认证:

请求路径: http://localhost:9101/oauth/token

参数:
grant_type :client_credentials
scope :access_token
client_id :client1
client_secret :client1_secret

在这里插入图片描述

10.2 密码认证:

请求路径: http://localhost:9101/oauth/token

参数:
grant_type :password
scope :access_token
client_id :client2
client_secret :client2_secret
username :admin
password:123

在这里插入图片描述

10.3 检查token是否合法

postman有两种方法带token

请求路径:http://localhost:9101/oauth/check_token?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsibXktcmVzb3VyY2UiXSwidXNlcl9uYW1lIjoidGVzdCIsInNjb3BlIjpbImFjY2Vzc190b2tlbiJdLCJleHAiOjE2MzIwODA3NTEsImF1dGhvcml0aWVzIjpbIlJPTEVfQURNSU4iXSwianRpIjoiZDk5NjY0MDktZDE3Ni00ZjNhLWFjNTItODk2NTY1MmVjNjkxIiwiY2xpZW50X2lkIjoiY2xpZW50MiJ9.6hRekdtvPzfDdKxP9b8E7CAWGB6PYXkqJuJ5VKvtRjk

第一种:url拼接
在这里插入图片描述
第二种:Authorzation的bearer 携带token
在这里插入图片描述
以上两种方法都可以

10.4 6.4 通过token访问controller

没带token:
在这里插入图片描述
带了token
在这里插入图片描述
没有oauth_client_details表会出现以下错误:
在这里插入图片描述
其他的没有表的情况下都是以下错误:
在这里插入图片描述

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值