基于mysql实现springboot+security+oauth用户认证功能

说明

基于mysql数据库存储client和用户数据,实现认证功能
基于redis实现springboot+security+oauth+mysql用户认证功能
基于jwt实现springboot+oauth2用户认证功能

框架

springboot 2.x + oauth2 + mysql

搭建过程如下:

1、建表语句

DROP TABLE IF EXISTS `oauth_access_token`;CREATE TABLE `oauth_access_token` (  `token_id` varchar(255) DEFAULT NULL COMMENT '加密的access_token的值',  `token` longblob COMMENT 'OAuth2AccessToken.java对象序列化后的二进制数据',  `authentication_id` varchar(255) DEFAULT NULL COMMENT '加密过的username,client_id,scope',  `user_name` varchar(255) DEFAULT NULL COMMENT '登录的用户名',  `client_id` varchar(255) DEFAULT NULL COMMENT '客户端ID',  `authentication` longblob COMMENT 'OAuth2Authentication.java对象序列化后的二进制数据',  `refresh_token` varchar(255) DEFAULT NULL COMMENT '加密的refresh_token的值') ENGINE=InnoDB DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `oauth_approvals`;CREATE TABLE `oauth_approvals` (  `userId` varchar(255) DEFAULT NULL COMMENT '登录的用户名',  `clientId` varchar(255) DEFAULT NULL COMMENT '客户端ID',  `scope` varchar(255) DEFAULT NULL COMMENT '申请的权限范围',  `status` varchar(10) DEFAULT NULL COMMENT '状态(ApproveDeny)',  `expiresAt` datetime DEFAULT NULL COMMENT '过期时间',  `lastModifiedAt` datetime DEFAULT NULL COMMENT '最终修改时间') ENGINE=InnoDB DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `oauth_client_details`;CREATE TABLE `oauth_client_details` (  `client_id` varchar(255) NOT NULL COMMENT '客户端ID',  `resource_ids` varchar(255) DEFAULT NULL COMMENT '资源ID集合,多个资源时用逗号(,)分隔',  `client_secret` varchar(255) DEFAULT NULL COMMENT '客户端密匙',  `scope` varchar(255) DEFAULT NULL COMMENT '客户端申请的权限范围',  `authorized_grant_types` varchar(255) DEFAULT NULL COMMENT '客户端支持的grant_type',  `web_server_redirect_uri` varchar(255) DEFAULT NULL COMMENT '重定向URI',  `authorities` varchar(255) DEFAULT NULL COMMENT '客户端所拥有的Spring Security的权限值,多个用逗号(,)分隔',  `access_token_validity` int(11) DEFAULT NULL COMMENT '访问令牌有效时间值(单位:)',  `refresh_token_validity` int(11) DEFAULT NULL COMMENT '更新令牌有效时间值(单位:)',  `additional_information` varchar(255) DEFAULT NULL COMMENT '预留字段',  `autoapprove` varchar(255) DEFAULT NULL COMMENT '用户是否自动Approval操作') ENGINE=InnoDB DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `oauth_client_token`;CREATE TABLE `oauth_client_token` (  `token_id` varchar(255) DEFAULT NULL COMMENT '加密的access_token值',  `token` longblob COMMENT 'OAuth2AccessToken.java对象序列化后的二进制数据',  `authentication_id` varchar(255) DEFAULT NULL COMMENT '加密过的username,client_id,scope',  `user_name` varchar(255) DEFAULT NULL COMMENT '登录的用户名',  `client_id` varchar(255) DEFAULT NULL COMMENT '客户端ID') ENGINE=InnoDB DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `oauth_code`;CREATE TABLE `oauth_code` (  `code` varchar(255) DEFAULT NULL COMMENT '授权码(未加密)',  `authentication` varbinary(255) DEFAULT NULL COMMENT 'AuthorizationRequestHolder.java对象序列化后的二进制数据') ENGINE=InnoDB DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `oauth_refresh_token`;CREATE TABLE `oauth_refresh_token` (  `token_id` varchar(255) DEFAULT NULL COMMENT '加密过的refresh_token的值',  `token` longblob COMMENT 'OAuth2RefreshToken.java对象序列化后的二进制数据 ',  `authentication` longblob COMMENT 'OAuth2Authentication.java对象序列化后的二进制数据') ENGINE=InnoDB DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `tb_permission`;
CREATE TABLE `tb_permission`
(
    `id`          bigint(20)   NOT NULL AUTO_INCREMENT,
    `parent_id`   bigint(20)   DEFAULT NULL COMMENT '父权限',
    `name`        varchar(64)  NOT NULL COMMENT '权限名称',
    `enname`      varchar(64)  NOT NULL COMMENT '权限英文名称',
    `url`         varchar(255) NOT NULL COMMENT '授权路径',
    `description` varchar(200) DEFAULT NULL COMMENT '备注',
    `created`     datetime     NOT NULL,
    `updated`     datetime     NOT NULL,
    PRIMARY KEY (`id`)
) ENGINE = InnoDB
  AUTO_INCREMENT = 44
  DEFAULT CHARSET = utf8 COMMENT ='权限表';
insert into `tb_permission`(`id`, `parent_id`, `name`, `enname`, `url`, `description`, `created`, `updated`)
values (37, 0, '系统管理', 'System', '/', NULL, '2019-04-04 23:22:54', '2019-04-04 23:22:56'),
       (38, 37, '用户管理', 'SystemUser', '/users/', NULL, '2019-04-04 23:25:31', '2019-04-04 23:25:33'),
       (39, 38, '查看用户', 'SystemUserView', '', NULL, '2019-04-04 15:30:30', '2019-04-04 15:30:43'),
       (40, 38, '新增用户', 'SystemUserInsert', '', NULL, '2019-04-04 15:30:31', '2019-04-04 15:30:44'),
       (41, 38, '编辑用户', 'SystemUserUpdate', '', NULL, '2019-04-04 15:30:32', '2019-04-04 15:30:45'),
       (42, 38, '删除用户', 'SystemUserDelete', '', NULL, '2019-04-04 15:30:48', '2019-04-04 15:30:45');

DROP TABLE IF EXISTS `tb_role`;
CREATE TABLE `tb_role`
(
    `id`          bigint(20)  NOT NULL AUTO_INCREMENT,
    `parent_id`   bigint(20)   DEFAULT NULL COMMENT '父角色',
    `name`        varchar(64) NOT NULL COMMENT '角色名称',
    `enname`      varchar(64) NOT NULL COMMENT '角色英文名称',
    `description` varchar(200) DEFAULT NULL COMMENT '备注',
    `created`     datetime    NOT NULL,
    `updated`     datetime    NOT NULL,
    PRIMARY KEY (`id`)
) ENGINE = InnoDB
  AUTO_INCREMENT = 38
  DEFAULT CHARSET = utf8 COMMENT ='角色表';
insert into `tb_role`(`id`, `parent_id`, `name`, `enname`, `description`, `created`, `updated`)
values (37, 0, '超级管理员', 'admin', NULL, '2019-04-04 23:22:03', '2019-04-04 23:22:05');

DROP TABLE IF EXISTS `tb_role_permission`;
CREATE TABLE `tb_role_permission`
(
    `id`            bigint(20) NOT NULL AUTO_INCREMENT,
    `role_id`       bigint(20) NOT NULL COMMENT '角色 ID',
    `permission_id` bigint(20) NOT NULL COMMENT '权限 ID',
    PRIMARY KEY (`id`)
) ENGINE = InnoDB
  AUTO_INCREMENT = 43
  DEFAULT CHARSET = utf8 COMMENT ='角色权限表';
insert into `tb_role_permission`(`id`, `role_id`, `permission_id`)
values (37, 37, 37),
       (38, 37, 38),
       (39, 37, 39),
       (40, 37, 40),
       (41, 37, 41),
       (42, 37, 42);

DROP TABLE IF EXISTS `tb_user`;
CREATE TABLE `tb_user`
(
    `id`       bigint(20)  NOT NULL AUTO_INCREMENT,
    `username` varchar(50) NOT NULL COMMENT '用户名',
    `password` varchar(64) NOT NULL COMMENT '密码,加密存储',
    `phone`    varchar(20) DEFAULT NULL COMMENT '注册手机号',
    `email`    varchar(50) DEFAULT NULL COMMENT '注册邮箱',
    `created`  datetime    NOT NULL,
    `updated`  datetime    NOT NULL,
    PRIMARY KEY (`id`),
    UNIQUE KEY `username` (`username`) USING BTREE,
    UNIQUE KEY `phone` (`phone`) USING BTREE,
    UNIQUE KEY `email` (`email`) USING BTREE
) ENGINE = InnoDB
  AUTO_INCREMENT = 38
  DEFAULT CHARSET = utf8 COMMENT ='用户表';
insert into `tb_user`(`id`, `username`, `password`, `phone`, `email`, `created`, `updated`)
values (37, 'admin', '$2a$10$9ZhDOBp.sRKat4l14ygu/.LscxrMUcDAfeVOEPiYwbcRkoB09gCmi', '15888888888',
        'lee.lusifer@gmail.com', '2019-04-04 23:21:27', '2019-04-04 23:21:29');

DROP TABLE IF EXISTS `tb_user_role`;
CREATE TABLE `tb_user_role`
(
    `id`      bigint(20) NOT NULL AUTO_INCREMENT,
    `user_id` bigint(20) NOT NULL COMMENT '用户 ID',
    `role_id` bigint(20) NOT NULL COMMENT '角色 ID',
    PRIMARY KEY (`id`)
) ENGINE = InnoDB
  AUTO_INCREMENT = 38
  DEFAULT CHARSET = utf8 COMMENT ='用户角色表';
insert into `tb_user_role`(`id`, `user_id`, `role_id`)
values (37, 37, 37);

表说明如下:
在这里插入图片描述
真正用到了红线内的表,后续用户数据也只是在代码里模拟

加入client数据

INSERT INTO `oauth`.`oauth_client_details`(`client_id`, `resource_ids`, `client_secret`, `scope`, `authorized_grant_types`, `web_server_redirect_uri`, `authorities`, `access_token_validity`, `refresh_token_validity`, `additional_information`, `autoapprove`) VALUES ('user_client', '', '123456', 'read,write', 'password,refresh_token', '', '', 7200, 1800, NULL, 'true');

在这里插入图片描述

2、pom依赖

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

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

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

        <!--mysql-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.0</version>
        </dependency>

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

        <!--druid-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.10</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>

        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>5.2.0</version>
        </dependency>

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

        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.8.2</version>
            <scope>test</scope>
        </dependency>

3、重写UserDetailsService接口实现

package com.yy.oauthmysql.service.impl;

import com.yy.oauthmysql.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

import java.util.Collections;

@Component
public class UserDetailServiceImpl implements UserDetailsService {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        /*模拟数据库操作*/
        User user = new User();
        user.setUsername("10086");
        user.setPassword("123456");
        return new org.springframework.security.core.userdetails
                .User(user.getUsername(), user.getPassword(), true, true, true, true, Collections.EMPTY_SET);
    }
}

4、websecurityconfig配置

package com.yy.oauthmysql.config;

import com.yy.oauthmysql.service.impl.UserDetailServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

import javax.swing.*;

/**
 * @author code
 * @Date 2022/7/6 10:50
 * Description security config
 * Version 1.0
 */
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Bean
    @Override
    public UserDetailsService userDetailsServiceBean() throws Exception {
        return new UserDetailServiceImpl();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsServiceBean()).passwordEncoder(passwordEncoder());
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
//        return NoOpPasswordEncoder.getInstance();
        return new CustomPasswordEncoder();
    }


    /**
     * 用于支持 password 模式 密码模式需要 AuthenticationManager 支持
     * password 模式一点要加上这个
     * @throws Exception
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    /**
     * 允许匿名访问所有接口 主要是 oauth 接口
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/**").permitAll();
        // 将登录框关闭
        http.formLogin().disable();
    }
}

5、加密说明

报错: Encoded password does not look like BCrypt

原因:SpringBoot版本的问题,1.x是明文,2.x是有加密

解决:
方式一:
使用 NoOpPasswordEncoder.getInstance();
在这里插入图片描述
方式二:
重写加密方法

package com.yy.oauthmysql.config;

import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * @author code
 * @Date 2022/7/7 14:11
 * Description 明文加密
 * Version 1.0
 */
public class CustomPasswordEncoder implements PasswordEncoder {
    @Override
    public boolean upgradeEncoding(String encodedPassword) {
        return false;
    }

    @Override
    public String encode(CharSequence charSequence) {
        return charSequence.toString();
    }

    @Override
    public boolean matches(CharSequence charSequence, String s) {
        return s.equals(charSequence.toString());
    }
}

在这里插入图片描述
6、认证服务器AuthorizationServerConfig

package com.yy.oauthmysql.config;

import com.yy.oauthmysql.service.impl.UserDetailServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
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.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;

import javax.sql.DataSource;
import java.util.concurrent.TimeUnit;

/**
 * @author code
 * @Date 2022/7/6 10:54
 * Description 认证服务器配置
 * Version 1.0
 */
@Configuration
@EnableAuthorizationServer   //注解开启了验证服务器
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private DataSource dataSource;

    // 声明TokenStore实现
    @Bean
    public TokenStore tokenStore() {
        return new JdbcTokenStore(dataSource);
    }

    // 声明 ClientDetails实现
    @Bean
    public ClientDetailsService clientDetails() {
        return new JdbcClientDetailsService(dataSource);
    }

    @Autowired
    private TokenStore tokenStore;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private ClientDetailsService clientDetails;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.jdbc(dataSource);
    }

    @Bean
    public UserDetailsService userDetailsService(){
        return new UserDetailServiceImpl();
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager);
        endpoints.tokenStore(tokenStore());
        endpoints.userDetailsService(userDetailsService());
        endpoints.setClientDetailsService(clientDetails);
        //配置TokenServices参数
        DefaultTokenServices tokenServices = new DefaultTokenServices();
        tokenServices.setTokenStore(endpoints.getTokenStore());
        tokenServices.setSupportRefreshToken(true);
        tokenServices.setClientDetailsService(endpoints.getClientDetailsService());
        tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());
        tokenServices.setAccessTokenValiditySeconds((int) TimeUnit.DAYS.toSeconds(1));
        endpoints.tokenServices(tokenServices);
    }

    @Bean
    @Primary
    public DefaultTokenServices tokenServices() {
        DefaultTokenServices tokenServices = new DefaultTokenServices();
        tokenServices.setSupportRefreshToken(true);
        tokenServices.setTokenStore(tokenStore);
        return tokenServices;
    }

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

7、资源服务器ResourceServerConfiguration

package com.yy.oauthmysql.config;

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;

/**
 * @author code
 * @Date 2022/7/6 15:46
 * Description 资源服务器
 * Version 1.0
 */
@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/**").permitAll();
    }

}

8、配置文件

server:
  port: 9010
spring:
  application:
    name: oauth2-as-jdbc
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/oauth?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
  main:
    allow-bean-definition-overriding: true
  security:
    user:
      name: admin
      password: admin

9、获取token
在这里插入图片描述
在这里插入图片描述

数据库表oauth_access_token
在这里插入图片描述

10、验证token
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值