• spring-cloud、spring-security、oauth、jwt


    Jwt 全称JSON Web Token,是无状态登录的一种实现方式。什么是无状态,就是服务端无状态,即无session。用户的登录状态由客户端保存,每次请求携带token,然后解析。多了不说,想了解更多的可以看https://www.jianshu.com/p/576dbf44b2ae,这里介绍的很详细

    先看看项目结构:

    ├─auth-server        
    │  ├─src
    │  │  ├─main
    │            ├─java
    │            │  └─com
    │            │      └─lhf
    │            │          └─authserver
    │            │              │  AuthServerApplication.java
    │            │              │  
    │            │              └─config
    │            │                      AuthServerConfig.java
    │            │                      SecurityConfig.java
    │            │                      
    │            └─resources
    │                │  application.properties
    │                │  
    │                ├─static
    │                └─templates                     
    │                          
    ├─resource-server         
    │  ├─src
    │  │  ├─main
    │            ├─java
    │            │  └─com
    │            │      └─lhf
    │            │          └─resourceserver
    │            │              │  ResourceServerApplication.java
    │            │              │  
    │            │              ├─config
    │            │              │      ResourceServerConfig.java
    │            │              │      
    │            │              └─controller
    │            │                      TestController.java
    │            │                      
    │            └─resources
    │                │  application.yml
    │                │  
    │                ├─static
    │                └─templates                                                  
    └─test        
        ├─src
        │  ├─main
                ├─java
                │  └─com
                │      └─lhf
                │          └─test
                │              │  TestApplication.java
                │              │  
                │              └─controller
                │                      TestController.java
                │                      
                └─resources
                    │  application.yml
                    │  
                    ├─static
                    └─templates
                            index.html                        

    可以看到,和上篇文章的结构一样。

    一、搭建授权服务器

    添加maven节点
         <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-oauth2</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-security</artifactId>
            </dependency>

    添加SecurityConfig.java

    package com.lhf.authserver.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.WebSecurityConfigurerAdapter;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    
    /**
     * <p></p>
     *
     * @author zy 刘会发
     * @version 1.0
     * @since 2020/5/11
     */
    @Configuration
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        /**
         * 密码比对器
         * @return
         */
        @Bean
        public PasswordEncoder passwordEncoder() {
            return new BCryptPasswordEncoder();
        }
    
        /**
         * 用户配置
         * @param auth
         * @throws Exception
         */
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.inMemoryAuthentication()
                    .withUser("admin").password(passwordEncoder().encode("123")).roles("admin");
        }
    
        /**
         * 安全配置,这里只是开启表单登录,不做其他配置,将交给资源服务器配置
         * @param http
         * @throws Exception
         */
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().disable().formLogin();
        }
    }

    添加AuthServerConfig.java

    package com.lhf.authserver.config;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    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 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.token.DefaultTokenServices;
    import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
    import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
    import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
    
    import javax.annotation.Resource;
    import java.util.Arrays;
    
    /**
     * <p></p>
     *
     * @author zy 刘会发
     * @version 1.0
     * @since 2020/5/11
     */
    @Configuration
    @EnableAuthorizationServer
    public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
    
        @Resource
        private ClientDetailsService clientDetailsService;
        @Autowired
        private PasswordEncoder passwordEncoder;
    
        /**
         * 授权服务器安全配置
         * @param security
         * @throws Exception
         */
        @Override
        public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
            security.checkTokenAccess("permitAll()").allowFormAuthenticationForClients();
        }
    
        /**
         * 授权服务客户端配置
         * @param clients
         * @throws Exception
         */
        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients.inMemory()
                    .withClient("novel")
                    .secret(passwordEncoder.encode("123"))
                    .autoApprove(true)
                    .resourceIds("lhf")
                    .scopes("all")
                    .redirectUris("http://localhost:8082/index.html")
                    .authorizedGrantTypes("authorization_code");
        }
    
        /**
         * 授权服务器节点配置
         * @param endpoints
         * @throws Exception
         */
        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
            endpoints.tokenServices(defaultTokenServices());
        }
    
        @Bean
        public DefaultTokenServices defaultTokenServices() {
            DefaultTokenServices bean = new DefaultTokenServices();
            bean.setTokenStore(jwtTokenStore());
            bean.setSupportRefreshToken(true);
            bean.setAccessTokenValiditySeconds(60 * 60);
            bean.setRefreshTokenValiditySeconds(30 * 60);
            bean.setClientDetailsService(clientDetailsService);
            TokenEnhancerChain chain = new TokenEnhancerChain();
            chain.setTokenEnhancers(Arrays.asList(jwtAccessTokenConverter()));//将token的增强方式注入进去
            bean.setTokenEnhancer(chain);
            return bean;
        }
    
        /**
         * token保存方式使用jwt
         * @return
         */
        @Bean
        public JwtTokenStore jwtTokenStore() {
            return new JwtTokenStore(jwtAccessTokenConverter());
        }
    
        /**
         * jwt配置
         * @return
         */
        @Bean
        public JwtAccessTokenConverter jwtAccessTokenConverter() {
            JwtAccessTokenConverter bean = new JwtAccessTokenConverter();
            bean.setSigningKey("zjs");
            return bean;
        }
    }

    和普通的方式没多大的差别,只是TokenStore的实现方式不同

    二、搭建资源服务

    maven节点和授权服务一样

    package com.lhf.resourceserver.config;
    
    import org.springframework.context.annotation.Bean;
    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;
    import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
    import org.springframework.security.oauth2.provider.token.RemoteTokenServices;
    import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
    import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
    
    /**
     * <p></p>
     *
     * @author zy 刘会发
     * @version 1.0
     * @since 2020/5/11
     */
    @Configuration
    @EnableResourceServer
    public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
    
        @Bean
        public RemoteTokenServices remoteTokenServices() {
            RemoteTokenServices bean = new RemoteTokenServices();
            bean.setClientId("novel");
            bean.setClientSecret("123");
            bean.setCheckTokenEndpointUrl("http://localhost:8080/oauth/check_token");
            return bean;
        }
    
        @Bean
        public JwtTokenStore jwtTokenStore() {
            return new JwtTokenStore(jwtAccessTokenConverter());
        }
    
        @Bean
        public JwtAccessTokenConverter jwtAccessTokenConverter() {
            JwtAccessTokenConverter bean = new JwtAccessTokenConverter();
            bean.setSigningKey("zjs");
            return bean;
        }
    
        @Override
        public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
            resources.tokenServices(remoteTokenServices()).resourceId("lhf").tokenStore(jwtTokenStore());
        }
    
        @Override
        public void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests().anyRequest().authenticated();
        }
    
    }

    同样的,资源服务器也得添加token的实现了,因为不再是默认的配置了。

    添加测试接口

    package com.lhf.resourceserver.controller;
    
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * <p></p>
     *
     * @author zy 刘会发
     * @version 1.0
     * @since 2020/5/11
     */
    @RestController
    public class TestController {
    
        @GetMapping("hello")
        public String hello() {
            return "hello";
        }
    }

    三、测试服务

    添加maven节点

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

    添加登录页面

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>第三方登录</title>
    </head>
    <body>
    <a href="http://localhost:8080/oauth/authorize?client_id=novel&response_type=code&scope=all&redirect_uri=http://localhost:8082/index.html">点击登录</a>
    <h2 th:text="${msg}"></h2>
    </body>
    </html>

    添加控制层

    package com.lhf.test.controller;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.HttpEntity;
    import org.springframework.http.HttpHeaders;
    import org.springframework.http.HttpMethod;
    import org.springframework.http.ResponseEntity;
    import org.springframework.stereotype.Controller;
    import org.springframework.util.LinkedMultiValueMap;
    import org.springframework.util.MultiValueMap;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.client.RestTemplate;
    import org.springframework.web.servlet.ModelAndView;
    
    import java.util.Map;
    
    /**
     * <p></p>
     *
     * @author zy 刘会发
     * @version 1.0
     * @since 2020/5/11
     */
    @Controller
    public class TestController {
    
        @Autowired
        private RestTemplate restTemplate;
    
        @GetMapping("index.html")
        public Object index(ModelAndView mv, String code) {
    
            mv.setViewName("index");
            if (code != null) {
                MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
                map.add("code", code);
                map.add("client_id", "novel");
                map.add("client_secret", "123");
                map.add("redirect_uri", "http://localhost:8082/index.html");
                map.add("grant_type", "authorization_code");
                Map<String, String> resp = restTemplate.postForObject("http://localhost:8080/oauth/token", map, Map.class);
                String access_token = resp.get("access_token");
                System.out.println(access_token);
                HttpHeaders headers = new HttpHeaders();
                headers.add("Authorization", "Bearer " + access_token);
                HttpEntity<Object> httpEntity = new HttpEntity<>(headers);
                ResponseEntity<String> entity = restTemplate.exchange("http://localhost:8081/hello", HttpMethod.GET, httpEntity, String.class);
                mv.addObject("msg", entity.getBody());
            }
            return mv;
        }
    }

    测试:

    请求 http://localhost:8082/index.html

     点击登录

     输入用户名密码,登录

    成功请求到资源服务

    项目源码地址:

    gitee: https://gitee.com/lhfas/security-jwt.git

    github: https://github.com/Liuhuifa/security-jwt.git

  • 相关阅读:
    解决"从不是创建控件的线程访问它"
    (转)Asp.net 中 Get和Post 的用法
    正则表达式30分钟入门教程 v2.3 转
    winform中,如何控制控件位置随窗体的大小改变而改变
    SpringCloudNetflix(Usage of Hystrix)
    SpringCloudNetflix(Usage of Eureka)
    分布式协调Zookeeper(分布式锁&Leader选举)
    SpringCloudNetflix(Usage of GateWay)
    分布式协调Zookeeper(手写配置中心&动态刷新)
    SpringCloudNetflix(Usage of Nacos配置中心)
  • 原文地址:https://www.cnblogs.com/Tiandaochouqin1/p/12872713.html
Copyright © 2020-2023  润新知