springcloud-sso单点登陆(一)

单点登陆的实现方式有多种:
1、基于cas来做
2、spring cloud oauth2的spring全家桶
3、自定义jwt(不推荐)
下面我们基于spring全家桶来做一个单点登陆系统2019年12月23日最新springboot版本2.2.2.RELEASE;由于篇幅问题,我们分成两篇文章。
下一篇:https://www.jianshu.com/p/074653aaa405
源码:https://github.com/xcocean/spring-cloud-sso

一、搭建统一依赖管理

项目maven父子项目结构:
parent(root)
      |__dependencies
      |__oauth2-server
      |__business-user

1、创建一个文件夹spring-cloud-sso用idea打开,然后new pom.xml:



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.2.2.RELEASE
         
    
    com.qbccn
    parent
    0.0.1-SNAPSHOT
    pom
    http://www.qbccn.com
    
        dependencies
    
    
        1.8
        ${java.version}
        ${java.version}
        UTF-8
        UTF-8
    

    
        
            
                com.qbccn
                dependencies
                ${project.version}
                pom
                import
            
        
    

    
        
            default
            
                true
            
            
                0.0.12
            
            
                
                    
                        io.spring.javaformat
                        spring-javaformat-maven-plugin
                        ${spring-javaformat.version}
                    
                    
                        org.apache.maven.plugins
                        maven-surefire-plugin
                        
                            
                                **/*Tests.java
                            
                            
                                **/Abstract*.java
                            
                            
                                file:/dev/./urandom
                                true
                            
                        
                    
                    
                        org.apache.maven.plugins
                        maven-enforcer-plugin
                        
                            
                                enforce-rules
                                
                                    enforce
                                
                                
                                    
                                        
                                            
                                                commons-logging:*:*
                                            
                                            true
                                        
                                    
                                    true
                                
                            
                        
                    
                    
                        org.apache.maven.plugins
                        maven-install-plugin
                        
                            true
                        
                    
                    
                        org.apache.maven.plugins
                        maven-javadoc-plugin
                        
                            true
                        
                        true
                    
                
            
        
    
    
        
            alimaven
            aliyun maven
            http://maven.aliyun.com/nexus/content/groups/public/
            
                false
            
        
        
            spring-milestone
            Spring Milestone
            https://repo.spring.io/milestone
            
                false
            
        
        
            spring-snapshot
            Spring Snapshot
            https://repo.spring.io/snapshot
            
                true
            
        
    
    
        
            spring-milestone
            Spring Milestone
            https://repo.spring.io/milestone
            
                false
            
        
        
            spring-snapshot
            Spring Snapshot
            https://repo.spring.io/snapshot
            
                true
            
        
    

然后在项目下创建一个文件夹dependencies,在dependencies下创建pom.xml:



    4.0.0
    com.qbccn
    dependencies
    0.0.1-SNAPSHOT
    pom
    http://www.qbccn.com

    
        
        2.1.4.RELEASE

        
        3.2.0
        2.1.1
        8.0.18

        
        3.14.2

        
        1.18.10
    

    
        
            
                org.projectlombok
                lombok
                ${lombok}
                true
            

            
            
                org.springframework.cloud
                spring-cloud-starter-oauth2
                ${spring-cloud-starter-oauth2}
            
            

            
                org.mybatis.spring.boot
                mybatis-spring-boot-starter
                ${mybatis-spring-boot-starter}
            

            
                com.zaxxer
                HikariCP
                ${HikariCP}
            
            
                org.springframework.boot
                spring-boot-starter-jdbc
                
                    
                    
                        org.apache.tomcat
                        tomcat-jdbc
                    
                
            
            
                mysql
                mysql-connector-java
                ${mysql-connector-java}
            

            
                com.squareup.okhttp3
                okhttp
                ${okhttp}
            
        
    

    
        
            alimaven
            aliyun maven
            http://maven.aliyun.com/nexus/content/groups/public/
            
                false
            
        
        
            spring-milestone
            Spring Milestone
            https://repo.spring.io/milestone
            
                false
            
        
        
            spring-snapshot
            Spring Snapshot
            https://repo.spring.io/snapshot
            
                true
            
        
    
    
        
            spring-milestone
            Spring Milestone
            https://repo.spring.io/milestone
            
                false
            
        
        
            spring-snapshot
            Spring Snapshot
            https://repo.spring.io/snapshot
            
                true
            
        
    

二、创建认证授权SSO:oauth2-server

spring-cloud-sso下创建文件夹oauth2-server,在oauth2-server下创建pom.xml



    4.0.0
    
        com.qbccn
        parent
        0.0.1-SNAPSHOT
    

    com.qbccn
    oauth2-server
    认证授权中心

    
        
            org.springframework.boot
            spring-boot-starter-thymeleaf
        
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.springframework.boot
            spring-boot-devtools
            runtime
            true
        
        
            org.projectlombok
            lombok
            true
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
            
                
                    org.junit.vintage
                    junit-vintage-engine
                
            
        

        
        
            org.springframework.cloud
            spring-cloud-starter-oauth2
        
        

        
            org.springframework.boot
            spring-boot-starter-data-redis
        
        
            org.mybatis.spring.boot
            mybatis-spring-boot-starter
        
        
            com.zaxxer
            HikariCP
        
        
            org.springframework.boot
            spring-boot-starter-jdbc
            
                
                
                    org.apache.tomcat
                    tomcat-jdbc
                
            
        
        
            mysql
            mysql-connector-java
        

        
            com.squareup.okhttp3
            okhttp
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
                
                    com.qbccn.Oauth2ServerApplication
                
            
        
    


在父pom.xml加上oauth2-server
然后关闭IDEA,重新打开让idea识别maven项目,更新项目。
然后手动创建src/main/javasrc/main/resources;在java下创建com.qbccn.Oauth2ServerApplication.java基本的springboot项目:

@SpringBootApplication
public class Oauth2ServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(Oauth2ServerApplication.class, args);
    }
}

关键配置如下
1、WebSecurityConfiguration

package com.qbccn.config;

import com.qbccn.config.impl.UserDetailsServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        // 设置默认的加密方式
        return new BCryptPasswordEncoder();
    }

    /**
     * 用于支持 password 模式
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

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

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 使用自定义认证与授权
        auth.userDetailsService(userDetailsService());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //关闭跨域认证
        http.csrf().disable();
        http.exceptionHandling()
                .and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }
}

2、AuthorizationServerConfiguration

package com.qbccn.config;

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.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
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.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private RedisConnectionFactory redisConnectionFactory;

    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    /**
     * 注入用于支持 password 模式
     */
    @Autowired
    private AuthenticationManager authenticationManager;

    @Bean
    public TokenStore tokenStore() {
        // 基于 redis 实现,令牌保存到redis,也可以存到数据库中
        return new RedisTokenStore(redisConnectionFactory);
    }

    @Bean
    @Primary
    public DefaultTokenServices defaultTokenServices() {
        DefaultTokenServices services = new DefaultTokenServices();
        services.setAccessTokenValiditySeconds(60 * 60 * 12);//设置token 20秒过期
        services.setRefreshTokenValiditySeconds(60 * 60 * 24 * 30);//设置刷新token的过期时间
        services.setTokenStore(tokenStore());
        return services;
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
                // 用于支持密码模式
                .authenticationManager(authenticationManager)
                .tokenStore(tokenStore());
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security
                // 允许客户端访问 /oauth/check_token 检查 token
                .checkTokenAccess("isAuthenticated()")
                .allowFormAuthenticationForClients();
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // 配置客户端,一般是读取数据库的,因为可能会变动,这里我们写死放在内存中即可
        clients
                // 使用内存设置
                .inMemory()
                // client_id
                .withClient("client")
                // client_secret
                .secret(passwordEncoder.encode("secret"))
                // 授权类型
                .authorizedGrantTypes("password", "refresh_token")
                //资源Id
                .resourceIds("backend-resources")
                // 授权范围
                .scopes("backend");
    }
}

3、UserDetailsServiceImpl

package com.qbccn.config.impl;

import com.qbccn.entity.SsoRole;
import com.qbccn.entity.SsoUser;
import com.qbccn.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
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.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

@Component
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UserService userService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 查询用户信息
        SsoUser user = userService.getUserInfo(username);
        if (user == null) {
            throw new UsernameNotFoundException("帐号:" + username + " 不存在!");
        }
        List grantedAuthorities = new ArrayList<>();
        //查询拥有的角色
        List roles = userService.getRoleByUserId(user.getId());
        roles.forEach(r -> {
            //security的验证规则需要ROLE_ 对应数据库的角色名称也要以ROLE_XXXX这种形式
            grantedAuthorities.add(new SimpleGrantedAuthority(r.getRoleName()));
        });
        //spring5+要求密码加密,这里传明文密码,所以再加密
        String password = new BCryptPasswordEncoder().encode(user.getPassword());
        return new User(user.getUsername(), password, grantedAuthorities);
    }
}

application.yml:

spring:
  main:
    allow-bean-definition-overriding: true
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/sso?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8
    username: root
    password: 123456
    hikari:
      minimum-idle: 1
      idle-timeout: 600000
      maximum-pool-size: 10
      auto-commit: true
      pool-name: MyHikariCP
      max-lifetime: 1800000
      connection-timeout: 30000
      connection-test-query: SELECT 1

  redis:
    port: 6379
    host: 127.0.0.1
    jedis:
      pool:
        min-idle: 1

mybatis:
  mapper-location: classpath:mapper/*.xml

SQL:

DROP TABLE IF EXISTS `sso_role`;
CREATE TABLE `sso_role` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) DEFAULT NULL,
  `role_name` varchar(30) DEFAULT NULL,
  `role_desc` varchar(50) DEFAULT NULL,
  `create_time` datetime DEFAULT NULL,
  `update_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

INSERT INTO `sso_role` VALUES ('1', '1', 'ROLE_USER', '用户角色', '2019-12-23 22:28:45', null);
INSERT INTO `sso_role` VALUES ('2', '2', 'ROLE_USER', '用户角色', '2019-12-23 22:28:45', null);
INSERT INTO `sso_role` VALUES ('3', '2', 'ROLE_ADMIN', '管理员', '2019-12-23 22:28:45', null);

DROP TABLE IF EXISTS `sso_user`;
CREATE TABLE `sso_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  `username` varchar(20) DEFAULT NULL,
  `password` varchar(20) DEFAULT NULL,
  `create_time` datetime DEFAULT NULL,
  `update_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

INSERT INTO `sso_user` VALUES ('1', '凌康', 'lk', '123', '2019-12-23 22:28:11', null);
INSERT INTO `sso_user` VALUES ('2', 'admin', 'admin', '123', '2019-12-23 22:28:23', null);

运行项目用postman测试:


image.png

项目结构如下


image.png

你可能感兴趣的:(springcloud-sso单点登陆(一))