Oauth2使用postman登录获取token

Oauth2使用postman登录获取token,第1张

Oauth2使用postman登录获取token
  1. 网关请求拦截-(CheckJwtFilter.java)

    package com.xiaoge.config;
    
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.xiaoge.constant.GatewayConstant;
    import org.apache.commons.lang.StringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.cloud.gateway.filter.GatewayFilter;
    import org.springframework.cloud.gateway.filter.GatewayFilterChain;
    import org.springframework.cloud.gateway.filter.GlobalFilter;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.Ordered;
    import org.springframework.core.io.buffer.DataBuffer;
    import org.springframework.core.io.buffer.DataBufferFactory;
    import org.springframework.data.redis.core.StringRedisTemplate;
    import org.springframework.http.HttpHeaders;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.server.reactive.ServerHttpRequest;
    import org.springframework.http.server.reactive.ServerHttpResponse;
    import org.springframework.util.CollectionUtils;
    import org.springframework.web.server.ServerWebExchange;
    import reactor.core.publisher.Mono;
    
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    /**
     * @Classname CheckJwtFilter
     * @Date 2022/3/20 下午4:49
     * @Created by xiaoge
     * @Description TODO
     */
    @Configuration
    public class CheckJwtFilter implements GlobalFilter, Ordered {
    
        @Autowired
        private StringRedisTemplate redisTemplate;
    
        /**
         * 过滤请求, 判断是否有jwt, 有放行, 没拦截
         * @param exchange
         * @param chain
         * @return
         */
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            ServerHttpRequest request = exchange.getRequest();
    
            // 获取路径
            String path = request.getURI().getPath();
    
            // 判断该路径是否在放行路径中
            if (GatewayConstant.ALLOW_PATH.contains(path)) {
                return chain.filter(exchange);
            }
    
            // 判断该请求头中是否包含Authorization
            HttpHeaders headers = request.getHeaders();
            List<String> list = headers.get(GatewayConstant.AUTHORIZATION);
            if (!CollectionUtils.isEmpty(list)) {
                String token = list.get(0);
    
                if (StringUtils.isNotBlank(token)) {
                    String jwt = token.replace("bearer ", "");
    
                    if (StringUtils.isNotBlank(jwt)) {
                        // 看redis是否还有该token
                        Boolean hasKey = redisTemplate.hasKey(GatewayConstant.OAUTH_PREFIX + jwt);
    
                        if(hasKey) {
                            return chain.filter(exchange);
                        }
                    }
                }
    
            }
    
            // 这里就是没有 jwt 了,返回 401
            ServerHttpResponse response = exchange.getResponse();
            // 设置响应头
            response.getHeaders().add("content-type", "application/json;charset=utf-8");
            Map<String, Object> map = new HashMap<>();
            map.put("code", HttpStatus.UNAUTHORIZED.value());
            map.put("msg", "非法访问!");
    
            ObjectMapper objectMapper = new ObjectMapper();
    
            byte[] bytes = null;
            try {
                bytes = objectMapper.writeValueAsBytes(map);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
    
            DataBuffer buffer = response.bufferFactory().wrap(bytes);
            return response.writeWith(Mono.just(buffer));
    
        }
    
    
        /**
         * 执行顺序 越小越先 要比-1 小
         * @return
         */
        @Override
        public int getOrder() {
            return -2;
        }
    }
    
    
  2. 网关配置把获取到的token存入redis-(GatewayConfig.java)它是把我们访问网关的路由转发到授权微服务

    package com.xiaoge.config;
    
    import cn.hutool.json.JSONObject;
    import cn.hutool.json.JSONUtil;
    import com.xiaoge.constant.GatewayConstant;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.cloud.gateway.route.RouteLocator;
    import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.core.StringRedisTemplate;
    import reactor.core.publisher.Mono;
    
    import java.time.Duration;
    import java.util.concurrent.TimeUnit;
    
    /**
     * @Classname GatewayConfig
     * @Date 2022/3/20 下午5:18
     * @Created by xiaoge
     * @Description TODO
     */
    @Configuration
    public class GatewayConfig {
    
        @Autowired
        private StringRedisTemplate redisTemplate;
    
        /**
         * 描述: 给授权专门做的存入 token 路由
         *
         * @param builder:
         * @return org.springframework.cloud.gateway.route.RouteLocator */
        @Bean
        public RouteLocator routeLocator(RouteLocatorBuilder builder) {
            return builder .routes()
                    .route("auth-server-router", r -> r.path("/oauth/**")
                            .filters(f -> f.modifyResponseBody(String.class, String.class, (exchanges, s) -> {
                                String path = exchanges.getRequest().getURI().getPath();
                                if ("/oauth/token".equals(path)) {
                                    //如果是登录的请求,那么得到的 s 就是 token 的一套
                                    JSONObject jsonObject = JSONUtil.parseObj(s);
    
                                    // 判断jsonObject 是否包含access_token
                                    if (jsonObject.containsKey("access_token")) {
                                        //如果包含 access_token 就放进 redis 里面
                                        // token值
                                        String access_token = jsonObject.getStr("access_token");
                                        // 过期时间
                                        Long expires_in = jsonObject.getLong("expires_in");
    
                                        // 存入redis中
                                        redisTemplate.opsForValue().set(GatewayConstant.OAUTH_PREFIX + access_token, "", Duration.ofSeconds(expires_in));
                                    }
                                }
                                return Mono.just(s);
                            })).uri("lb://auth-server"))
                    .build();
    
        }
    }
    
  3. 授权服务认证配置-(AuthorizationConfig.java)

    package com.xiaoge.config;
    
    import com.xiaoge.service.impl.UserDetailsServiceImpl;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.io.ClassPathResource;
    import org.springframework.security.authentication.AuthenticationManager;
    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.configurers.AuthorizationServerEndpointsConfigurer;
    import org.springframework.security.oauth2.provider.token.TokenStore;
    import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
    import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
    import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;
    
    import java.security.KeyPair;
    
    /**
     * @Author: ZhangXiao
     * @DateTime: 2022/4/7 15:59
     * @Description:
     * 1. token的存储
     * 2. jwt的转换器
     * 3. 第三方应用
     * 4. endpoints暴露
     */
    @Configuration
    public class AuthorizationConfig extends AuthorizationServerConfigurerAdapter {
    
        @Autowired
        private PasswordEncoder passwordEncoder;
    
        @Autowired
        private AuthenticationManager authenticationManager;
    
        @Autowired
        private UserDetailsServiceImpl userDetailsService;
    
        /**
         * 使用 jwt 存放 token
         * @return
         */
        @Bean
        public TokenStore tokenStore() {
            return new JwtTokenStore(jwtAccessTokenConverter());
        }
    
    
        /**
         * 使用非对称加密的方式
         * @return
         */
        @Bean
        public JwtAccessTokenConverter jwtAccessTokenConverter() {
            JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
            // 把私钥读到内存中
            ClassPathResource resource = new ClassPathResource("cxs-jwt.jks");
            // 创建一个钥匙工厂
            KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(resource,"cxs123".toCharArray());
            // 获取钥匙, 传入钥匙别名
            KeyPair privateKey = keyStoreKeyFactory.getKeyPair("cxs-jwt");
            // 设置进转换器里面
            jwtAccessTokenConverter.setKeyPair(privateKey);
            return jwtAccessTokenConverter;
        }
    
    
        /**
         * 配置第三方应用
         * password 只要是登录都用这个授权方式
         * 客户端授权 用于微服务之间自发的进行远程调用时 资源服务器必须要token的情况, 当然也是可以放行服务提供者的接口的
         *
         *
         * 描述: 一个 web 平台,用于第三方访问
         * 一个 sxt 平台,内部访问的,例如 mq 里发起远程调用
         * @param clients
         * @throws Exception
         */
        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients.inMemory() // 配置第三方引用
                        .withClient("web") // 浏览器
                        .secret(passwordEncoder.encode("web-secret")) // 密码加密方式
                        .scopes("all")  // 作用域
                        .authorizedGrantTypes("password") // 授权类型 密码授权
                        .accessTokenValiditySeconds(7200) // token的时间7200秒
                        .redirectUris("https://www.baidu.com") // token过期从定向地址
                        .and() // 上面是密码授权方式, 下面是客户端授权
                        .withClient("client") // 微服务之间自发的调用
                        .secret(passwordEncoder.encode("client-secret")) // 密码加密方式
                        .scopes("read") // 只读 业务方面的一个配置
                        .authorizedGrantTypes("client_credentials") // 授权类型  客户端授权
                        .accessTokenValiditySeconds(Integer.MAX_VALUE) // token过期时间 66年
                        .redirectUris("https://www.baidu.com");  // token过期从定向地址
    
        }
    
    
        /**
         * 暴露出去
         * @param endpoints
         * @throws Exception
         */
        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
            endpoints
                    .userDetailsService(userDetailsService)  // 暴露密码登录实现类
                    .authenticationManager(authenticationManager) // 暴露密码登录需要的认证管理器
                    .tokenStore(tokenStore())  // 暴露tokenStore
                    .accessTokenConverter(jwtAccessTokenConverter()); // 暴露jwt转换器
            super.configure(endpoints);
        }
    
    }
    
  4. 授权服务安全配置-(WebSecurityConfig.java)

    package com.xiaoge.config;
    
    import com.xiaoge.service.impl.UserDetailsServiceImpl;
    import org.springframework.beans.factory.annotation.Autowired;
    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.web.configuration.WebSecurityConfigurerAdapter;
    
    /**
     * @Author: ZhangXiao
     * @DateTime: 2022/4/7 15:56
     * @Description:
     */
    @Configuration
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Autowired
        private UserDetailsServiceImpl userDetailsService;
    
        /**
         * 认证管理器 密码登录需要认证管理器
         * @return
         * @throws Exception
         */
        @Bean
        public AuthenticationManager authenticationManager() throws Exception {
            return super.authenticationManager();
        }
    
    
        /**
         * 走自己的登录 密码登录需要的
         * @param auth
         * @throws Exception
         */
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            //走自己的登录
            auth.userDetailsService(userDetailsService);
        }
    
    }
    
  5. 授权服务登录-(UserDetailsServiceImpl.java)

    package com.xiaoge.service.impl;
    
    import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
    import com.xiaoge.constant.AuthConstant;
    import com.xiaoge.domain.SysUser;
    import com.xiaoge.mapper.SysUserMapper;
    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.stereotype.Service;
    import org.springframework.util.CollectionUtils;
    import org.springframework.util.ObjectUtils;
    import org.springframework.util.StringUtils;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    
    import javax.servlet.http.HttpServletRequest;
    import java.util.List;
    
    /**
     * @Author: ZhangXiao
     * @DateTime: 2022/4/7 16:10
     * @Description:
     */
    @Service
    public class UserDetailsServiceImpl implements UserDetailsService {
    
        @Autowired
        private SysUserMapper sysUserMapper;
    
        /**
         * 登录方法
         * @param username
         * @return
         * @throws UsernameNotFoundException
         */
        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
            // 获取request
            ServletRequestAttributes requestAttributes =  (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = requestAttributes.getRequest();
    
            // 获取请求头信息
            String loginType = request.getHeader(AuthConstant.LOGIN_TYPE);
    
            if (StringUtils.isEmpty(loginType)) {
                return null;
            }
    
            // 选择
            switch (loginType) {
                case AuthConstant.SYS_USER:
                    // 后台用户 就查后台的sys_user表
                    SysUser sysUser = sysUserMapper.selectOne(new LambdaQueryWrapper<SysUser>().eq(
                            SysUser::getUsername, username
                    ));
    
                    if (!ObjectUtils.isEmpty(sysUser)) {
                        // 查询权限
                        List<String> auths = sysUserMapper.findUserAuthsById(sysUser.getUserId());
    
                        if (!CollectionUtils.isEmpty(auths)) {
                            // 设置权限
                            sysUser.setAuths(auths);
                        }
                    }
                    return sysUser;
                case AuthConstant.MEMBER:
                    // 前台用户
                    return null;
                default:
                    return null;
    
            }
        }
    }
    
  6. 授权服务启动类-(AuthServerApplication.class) (一定要加这个认证注解EnableAuthorizationServer, 因为WebSecurityConfig配置了认证管理器)

    package com.xiaoge;
    
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    import org.springframework.context.annotation.Bean;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
    
    /**
     * @Author: ZhangXiao
     * @DateTime: 2022/4/7 15:36
     * @Description:
     */
    @SpringBootApplication
    @EnableAuthorizationServer // 开启授权服务器
    @EnableEurekaClient  // 开启eureka客户端
    @MapperScan(basePackages = "com.xiaoge.mapper")
    public class AuthServerApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(AuthServerApplication.class, args);
        }
    
    
        /**
         * 密码加密器
         * @return
         */
        @Bean
        public PasswordEncoder passwordEncoder(){
            return new BCryptPasswordEncoder();
        }
    
    }
    
  7. postman-Authorization(web web-secret grant_type(认证方式)是AuthorizationConfig类中配置的)

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/874647.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-13
下一篇 2022-05-13

发表评论

登录后才能评论

评论列表(0条)

保存