SpringCloud-Alibaba+oauth 单点登陆

1.创建工程

        创建父工程SpringAuth

        修改pom文件

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.2</version>
        <relativePath/>
    </parent>
    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.4.2</spring-boot.version>
        <spring-cloud.version>2020.0.1</spring-cloud.version>
        <spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version>
    </properties>


    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
        创建子工程

        分别创建cloud-auth用于授权认证,cloud-comm用于存放公共类,cloud-service用于存放业务,cloud-gateway用于存放网关

        cloud-comm

    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
    </dependencies>
server:
  port: 8081
spring:
  application:
    name: auth-comm
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848

        cloud-auth

    <dependencies>
        <dependency>
            <groupId>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth2</artifactId>
            <version>2.3.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>cloud-comm</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-jwt</artifactId>
            <version>1.1.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.18</version>
        </dependency>
    </dependencies>
server:
  port: 8082
spring:
  application:
    name: auth-auth
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
      config:
        server-addr: localhost:8848
        file-extension: yaml

2.编辑工程

        cloud-auth授权码模式
package com.cloud.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/oauth/**","/").permitAll() //oauth的路径全部放行
                .anyRequest().authenticated()  //其他接口需要认证
                .and()
                .formLogin().permitAll();  //放行登陆接口
        http.csrf().disable().cors();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .passwordEncoder(passwordEncoder())
                .withUser("yzx")
                .password(passwordEncoder().encode("123456"))
                .roles("ADMIN");
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
}
package com.cloud.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.password.PasswordEncoder;
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 javax.annotation.Resource;

@Configuration
@EnableAuthorizationServer  //认证服务器
public class OauthConfig extends AuthorizationServerConfigurerAdapter {

    @Resource
    private PasswordEncoder passwordEncoder;
    //第三方客户端的信息
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()//表示配置第三方客户端信息
                .withClient("admin")//设置的第三方客户端选项client_id,第三方登陆的名字
                .secret(passwordEncoder.encode("aa"))//对应oauth协议一个属性,client_secret,第三方登陆密码
                .authorizedGrantTypes("authorization_code","refresh_token")//对应授权的模式是什么,第二个参数代表可以获取刷新的token
        /*
        authorization_code  授权码模式
        password    密码模式
        implicit    简单模式
        client_credentials  客户端模式
         */
                .redirectUris("http://localhost:8082")//从哪里拿到code
                .autoApprove(true)//是否自动授权
                .scopes("all");//授权的范围
        /*
        /oauth/authoriz 授权端点
        /oauth/token    获取token
        /oauth/check    检验token
         */
    }
}
package com.cloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

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

        进行启动

localhost:8082/oauth/authorize?response_type=code&client_id=admin&scope=all

        因为/路径没有内容,所以会404页面,但在url地址栏会携带一个code参数,将该值拿到,该值为授权码 

        然后通过该授权码来生成token,

localhost:8082/oauth/token?grant_type=authorization_code

&code=VvxTRs&client_id=admin&redirect_url=http://localhost:8082&scope=all

        第一个参数表示授权的模式是什么,第二个是授权码,第三个是第三方登陆的用户是谁,第四个是把token返回到哪里

        使用postman进行厕所,生成token,需要携带着第三方信息

        access_token:生成的token

        token_type:token的类型

        refresh_token:该token的有效期是access_token有效期的两倍

        expires_in:有效期 

        总结:搭建授权认证服务器,在oauth配置文件种设置授权模式,访问授权站点得到授权码,通过授权码获得token

        cloud-auth简单模式

        修改oauth配置类

        访问

localhost:8082/oauth/authorize?response_type=token&client_id=admin&scope=all

        登陆得到地址

http://localhost:8082/#access_token=ac55179f-0e70-4a34-ad27-29506cc719b2&token_type=bearer&expires_in=43199

        地址即包括了token

        cloud-auth客户端模式

         cloud-auth密码模式

        修改SecurityConfig类,重写authenticationManager()方法,并注入到spring容器

    @Override
    @Bean
    protected AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }

         修改OauthConfig类,将AuthenticationManager注入进来,并重写configure()方法

    @Resource
    private AuthenticationManager authenticationManager;

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager);
    }

         访问时需要携带第三方用户名和密码以及security登陆的用户名和密码‘

3.生成token

        修改cloud-auth

        修改config类

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
        endpoints.authenticationManager(authenticationManager);
        endpoints.tokenStore(getTokenStore());
        endpoints.accessTokenConverter(getConverter());//生成jwt,解析jwt
    }

    @Bean
    public TokenStore getTokenStore(){
        return new JwtTokenStore(getConverter());
    }

    /*
    解析,生成jwt
     */
    @Bean
    public JwtAccessTokenConverter getConverter() {
        JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
        jwtAccessTokenConverter.setSigningKey("yzx");
        return jwtAccessTokenConverter;
    }

        使用密码模式访问获取token

        配置放行路径

        配置config类 

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.allowFormAuthenticationForClients()
                .checkTokenAccess("permitAll()")//放行oauth/check_token路径
                .tokenKeyAccess("permitAll()");//放行oauth/token路径
    }

        然后重新使用密码模式获取token,在授权使用无授权方式进行获取,也可以获取到token

        校验token

        将刚刚获取到的token进行校验,使用get方式

localhost:8082/oauth/check_token?token=传入token值

4.资源服务器

        在cloud-service工程下创建service-product工程,添加启动类,依赖,配置文件

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth2</artifactId>
            <version>2.3.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security.oauth.boot</groupId>
            <artifactId>spring-security-oauth2-autoconfigure</artifactId>
        </dependency>
    </dependencies>
server:
  port: 8083

spring:
  application:
    name: service-product
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848

        创建控制层和配置类

@RestController
@RequestMapping("/product")
public class ProductController {
    @GetMapping("/info")
    @PreAuthorize("hasRole('ADMIN')")
    public String info(){
        return "hello world";
    }
}
@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true,jsr250Enabled = true)
public class ProductConfig extends ResourceServerConfigurerAdapter {
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().authenticated()//配置所有路径都需要认证
                .and()
                .csrf().disable();
    }
    @Bean
    public TokenStore getTokenStore(){
        return new JwtTokenStore(getConverter());
    }

    /*
    解析,生成jwt
     */
    @Bean
    public JwtAccessTokenConverter getConverter() {
        JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
        jwtAccessTokenConverter.setSigningKey("yzx");
        return jwtAccessTokenConverter;
    }
}
        携带token访问

        security默认获取请求头中的token值,key为Authorization,值为beare的token

        bearer拼接token值

        登陆成功,返回token给前端

        cloud-auth,修改security配置类

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/oauth/**","/","/login").permitAll() //oauth的路径全部放行
                .anyRequest().authenticated()  //其他接口需要认证
                .and()
                .formLogin().permitAll();  //放行登陆接口
        http.csrf().disable().cors();
        http.formLogin().loginProcessingUrl("/login").successHandler(getSuccessHandler());
    }

    @Bean
    public AuthenticationSuccessHandler getSuccessHandler() {
        return (httpServletRequest, httpServletResponse, authentication) -> {
            HttpRequest post = HttpUtil.createPost("http://localhost:8082/oauth/token");
            post.form("grant_type","password");
            post.form("client_id","admin");
            post.form("client_secret","aa");
            post.form("username",httpServletRequest.getParameter("username"));
            post.form("password",httpServletRequest.getParameter("password"));
            HttpResponse execute = post.execute();//执行
            Token token = JSON.parseObject(execute.body(), Token.class);
            ReturnData(httpServletResponse,new Result(200,"登陆成功",token));
        };
    }

    private void ReturnData(HttpServletResponse response, Result result){
        response.setContentType("application/json;charset=utf-8");
        try {
            PrintWriter writer = response.getWriter();
            writer.println(result.getData());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.75</version>
        </dependency>
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Token {
    private String access_token;
    private Integer expires_in;
    private String scope;
    private String jti;
}

        在成功登陆后,调用successHadler方法,进行发送请求获取token,然后将token返回给前端

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值