IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 微服务+vue架构+oauth2+权限系统的实现 -> 正文阅读

[JavaScript知识库]微服务+vue架构+oauth2+权限系统的实现

思路: 1.登录认证oauth/token拦截器 2找到user信息 3.利用user字段得到token,返回赋值给session 4请求权限信息,网管拦截 ,用token去经过网关解析成id 5、跳转微服务getinfo,获取id查询用户权限角色。
开发技巧:代码一点一点的加,一点一点的测试,如果错了可以返回上一步。有时候加多了,他会报不相干的错误,比如因为加了dao层进行了跨域。
网关不过滤就重启

1.网关配置:拦截器实现,要放行oauth/token,所有请求接口经过网关ip转发。
网关白名单放行/yz/oauth/token,也经过网关拦截过滤器, (网关都要加前缀,好进行分发),其他请求都要经过网关拦截器验证token。
第一次请求自带的token参数代表了clientid 和clientsecret在这里插入图片描述

网关拦截器,把token 存在request中

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String token = exchange.getRequest().getHeaders().getFirst("Authorization");
        if (StrUtil.isEmpty(token)) {
            return chain.filter(exchange);
        }
        if (token.startsWith("bearer")) {
            try {
                //从token中解析用户信息并设置到Header中去
                System.out.println("从token中解析用户信息并设置到Header中去");
                String realToken = token.replace("bearer ", "");
                JWSObject jwsObject = JWSObject.parse(realToken);
                String userStr = jwsObject.getPayload().toString();
                System.out.println(userStr);
                //信息加入到head里面。
                ServerHttpRequest request = exchange.getRequest().mutate().header("user", userStr).build();
                try {
                    userStr= URLEncoder.encode(userStr, "UTF-8");
                }catch (Exception e){
                    e.printStackTrace();
                }
                request = exchange.getRequest().mutate().header("enuser", userStr).build();
                exchange = exchange.mutate().request(request).build();
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        return chain.filter(exchange);
    }

在这里插入图片描述

大坑,ip不要用前端映射,其实是需要重启。有缓存。在这里插入图片描述

网关搭建
请添加图片描述
2.配置认证服务器
任何接口资源/users/me都要微服务这里放行,不带yz网关前缀,因为是网关转过来的。

认证服务器请求拦截器,每个服务都有
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll()
                // @link https://gitee.com/xiaoym/knife4j/issues/I1Q5X6 (接口文档knife4j需要放行的规则)
                .antMatchers("/webjars/**","/doc.html","/swagger-resources/**","/v2/api-docs").permitAll()
                .antMatchers("/rsa/publicKey","/decode" ,"/users/me","/sys/menus","/sys/menus_cbs","/redirect").permitAll()
                .anyRequest().authenticated()
                .and()
                .csrf().disable();
    }

在这里插入图片描述

oauth2配置客户端
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        System.out.println("[2]----加载认证服务配置");
        clients.inMemory()
             .withClient("client-api")
                .secret(passwordEncoder.encode("123456"))
                .scopes("all")
                .authorizedGrantTypes("password", "refresh_token")
                .accessTokenValiditySeconds(60 * 60 * 5)//token 有效期15分钟
                .refreshTokenValiditySeconds(60 * 60 * 10)//有效期内可以刷新token
                .and()
             .withClient("client-jump")
                .secret(passwordEncoder.encode("123456"))
                .scopes("all")
                .authorizedGrantTypes("password", "refresh_token")
                .accessTokenValiditySeconds(60 * 15)//token 有效期15分钟
                .refreshTokenValiditySeconds(60 * 30)//有效期内可以刷新token
                .and()
             .withClient("client-app")
                .secret(passwordEncoder.encode("123456"))
                .scopes("all")
                .authorizedGrantTypes("password", "refresh_token")
                .accessTokenValiditySeconds(60 * 15)//token 有效期15分钟
                .refreshTokenValiditySeconds(60 * 30);//有效期内可以刷新token
    }
oauth2配令牌服务,产生token,需要userDetailsService作为生成token的参数
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
        List<TokenEnhancer> delegates = new ArrayList();
        delegates.add(tokenEnhancer());
        delegates.add(accessTokenConverter());
        enhancerChain.setTokenEnhancers(delegates); //配置JWT的内容增强器
        endpoints.authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService) //配置加载用户信息的服务,对比的用的userDetailsService查找信息
                .accessTokenConverter(accessTokenConverter())
                .reuseRefreshTokens(false)
                .tokenEnhancer(enhancerChain);
    }
token生成的字段
    public TokenEnhancer tokenEnhancer() {
        return (accessToken, authentication) -> {
            Map<String, Object> additionalInfo = CollectionUtil.newHashMap();
            SecurityUser OAuthUserDetails = (SecurityUser) authentication.getPrincipal();
//            additionalInfo.put("userId", OAuthUserDetails.getId());
            additionalInfo.put("oilfield", OAuthUserDetails.getOilfield());
            additionalInfo.put("dataSource", OAuthUserDetails.getDataSource());
            additionalInfo.put("unitid", OAuthUserDetails.getUnitid());
            additionalInfo.put("user_Id", OAuthUserDetails.getUser_Id());
            additionalInfo.put("truename", OAuthUserDetails.getRealname());
            additionalInfo.put("unitname", OAuthUserDetails.getUnitname());
            additionalInfo.put("username", OAuthUserDetails.getUsername());
//            additionalInfo.put("id", OAuthUserDetails.getId());
            ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
            return accessToken;
        };
    }

请添加图片描述

3.前端 js认证请求post

 loginForm: {
          username: 'admin',
          password: '123456',
          grant_type:'passwrod',//密码认证模式,passwrod写错了,错一个字母,就要排查好一会错误bug
          client_secret:'123456',
          client_id:'client-app'
        },


 axios.post(`/api/yz/oauth/token?username=${loginForm.username}&password=${loginForm.password}&grant_type=${loginForm.grant_type}`,
            loginForm, { headers: { Authorization: 'Basic Y2xpZW50LWFwcDoxMjM0NTY=' } }
          ).then((res) => {
            debugger;
               if (res.msg === "success") {
            //使用session存储token值
                 sessionStorage.setItem('cloud-ida-token',res.data);
            //cookie中保存前端登录状态
                 setToken();
                }
               resolve(res);
            }).finally(() => {
              this.loading = false
            })
            setTimeout(() => {
              // console.log(this.$route.params.from)
              //  window.location.replace(this.$route.params.from || '/jxzy02')
            })
          }).finally(() => {
            //this.loadin
          });

返回参数跳转
     handleLogin() {
        this.$refs.loginForm.validate(valid => {
          if (valid) {
            this.loading = true
            this.$store.dispatch('Login', this.loginForm).then(data => {
              console.log('获取到的data: '+data.msg);
              this.loading = false
              if ("success" === data.msg) {
                this.$router.push({path: '/'})
              } else {
                this.$message.error("账号/密码错误");
              }
            }).catch(() => {
              this.loading = false
            })
          } else {
            return false
          }
        })
      }
    }
  }

请添加图片描述
4.认证后台,对比账号,先用username查询,后面用userid查询

 `    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        System.out.println("[4]---loadUserByUsername");
//        List<UserDTO> findUserList = userList.stream().filter(item -> item.getUsername().equals(username)).collect(Collectors.toList());
        UserDTO userDTO=new UserDTO();//实体类
        userDTO.setUser_name(username);
        List<UserDTO> findUserList = dao.find("loadUserByUsername",userDTO);//查询
        if (CollUtil.isEmpty(findUserList)) {
            throw new UsernameNotFoundException(MessageConstant.USERNAME_PASSWORD_ERROR);
        }
        userDTO = findUserList.get(0);
        userDTO.setStatus(1);
        userDTO.setRoles(CollUtil.toList("ADMIN"));
        //数据库中的密码(需前端传递过来md5加密的密码)
      userDTO.setPassword(passwordEncoder.encode(userDTO.getPassword().toLowerCase()));

        SecurityUser securityUser = new SecurityUser(userDTO);
        if (!securityUser.isEnabled()) {
            throw new DisabledException(MessageConstant.ACCOUNT_DISABLED);
        } else if (!securityUser.isAccountNonLocked()) {
            throw new LockedException(MessageConstant.ACCOUNT_LOCKED);
        } else if (!securityUser.isAccountNonExpired()) {
            throw new AccountExpiredException(MessageConstant.ACCOUNT_EXPIRED);
        } else if (!securityUser.isCredentialsNonExpired()) {
            throw new CredentialsExpiredException(MessageConstant.CREDENTIALS_EXPIRED);
        }
        return securityUser;
    }
`

在这里插入图片描述
在这里插入图片描述
跳转到配置里的token 生成,把需要的字段添加进去,然后在第二次请求token解析的时候可以拿到字段

   @Bean
    public TokenEnhancer tokenEnhancer() {
        return (accessToken, authentication) -> {
            Map<String, Object> additionalInfo = CollectionUtil.newHashMap();
            SecurityUser OAuthUserDetails = (SecurityUser) authentication.getPrincipal();
//            additionalInfo.put("userId", OAuthUserDetails.getId());
            additionalInfo.put("oilfield", OAuthUserDetails.getOilfield());
            additionalInfo.put("dataSource", OAuthUserDetails.getDataSource());
            additionalInfo.put("unitid", OAuthUserDetails.getUnitid());
            additionalInfo.put("user_Id", OAuthUserDetails.getUser_Id());
            additionalInfo.put("truename", OAuthUserDetails.getRealname());
            additionalInfo.put("unitname", OAuthUserDetails.getUnitname());
            additionalInfo.put("username", OAuthUserDetails.getUsername());
//            additionalInfo.put("id", OAuthUserDetails.getId());
            ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
            return accessToken;
        };
    }

在这里插入图片描述

5.返回js处理,保存token到session下次发送请求带上,设置cookie已经登录的状态。

token的保存格式要和图中一样。中间加个空格。。
在这里插入图片描述

在这里插入图片描述

  // 登录返回处理
    Login({commit, state}, loginForm) {
      return new Promise((resolve, reject) => {
          this.loading = true
          axios.post(`/api/oauth/token?username=${loginForm.username}&password=${loginForm.password}&grant_type=${loginForm.grant_type}&client_secret=${loginForm.client_secret}&client_id=${loginForm.client_id}`,
            loginForm, { headers: { Authorization: 'Basic Y2xpZW50LWFwcDoxMjM0NTY=' } }
          ).then((r) => {
            debugger;
            r=r.data;
               if (r.msg === "操作成功") {
            //使用session存储token值,,,,,,有一定的格式
                 sessionStorage.setItem('cloud-ida-token',r.data.access_token);
            //cookie中保存前端登录状态
                 setToken();
                }
               resolve(r);
            }).finally(() => {
              this.loading = false
            })
            setTimeout(() => {
              // console.log(this.$route.params.from)
              //  window.location.replace(this.$route.params.from || '/jxzy02')
            })
          }).finally(() => {
            //this.loadin
          });

cookie在登出的时候得清除掉,否则自动去getinfo,,, setToken()方法

import Cookies from 'js-cookie'
const LoginKey = 'hasLogin'//设置coolie已经登录
export function getToken() {
  return Cookies.get(LoginKey);
}
export function setToken() {
  return Cookies.set(LoginKey, "1")
}
export function removeToken() {
  return Cookies.remove(LoginKey)
}

在这里插入图片描述

每次请求的axios处理

import axios from 'axios'
import {Message, MessageBox} from 'element-ui'
import {getToken} from '@/utils/auth'
import store from '../store'
// 创建axios实例
const service = axios.create({
  baseURL: process.env.BASE_URL, // api的base_url
  timeout: 15000                  // 请求超时时间2
})
// request拦截器
service.interceptors.request.use(config => {
  config.headers.Authorization=sessionStorage.getItem('cloud-ida-token');//每次请求都要加token
  return config
}, error => {
  // Do something with request error
  console.error(error) // for debug
  Promise.reject(error)
})
// respone拦截器
service.interceptors.response.use(
  response => {
    const res = response.data;
    if (res.code == "200") {
      return res
    }

    if (res.code == '10002') {
      Message({
        showClose: true,
        message: res.msg,
        type: 'error',
        duration: 3 * 1000,
        onClose: () => {
          store.dispatch('FedLogOut').then(() => {
            location.reload()// 为了重新实例化vue-router对象 避免bug
          })
        }
      });
      return Promise.reject(res.msg)
    }else{
      Message({
        message: res.msg,
        type: 'error',
        duration: 3 * 1000
      })
      return res
    }
  },
  error => {
    console.error('err' + error)// for debug
    Message({
      message: error.message,
      type: 'error',
      duration: 3 * 1000
    })
    return Promise.reject(error)
  }
)
export default service

7前端配置
跨域设置,认证完经过网关跳转不了微服务可能是跨域问题,,,也可能是接口输错了user/mehhhe和users、me、()dakeng大坑在这里插入图片描述
8,getinfo带着token去网关验证得到id,放在request的header里,跳转到微服务中取出,然后获取信息。

先建表,bean,mapper接口和xml,service,controull层
springboot找不到dao
跨域问题

编译错误

在这里插入图片描述

看返回,返回失败,跳转到login
在这里插入图片描述
请添加图片描述

import router from './router'
import store from './store'
import NProgress from 'nprogress' // Progress 进度条
import 'nprogress/nprogress.css' // Progress 进度条样式
import {getToken} from '@/utils/auth' // 验权
const whiteList = ['/login', '/404'] //白名单,不需要登录的路由
router.beforeEach((to, from, next) => {
  NProgress.start()
  if (getToken()) {
    //如果已经登录

    if (to.path === '/login') {
      next({path: '/'})
      NProgress.done() // 结束Progress
    } else if (!store.getters.role) {
      //跳转后台
      store.dispatch('GetInfo').then(() => {
        next({...to})
      })
    } else {
      next()
    }
  } else if (whiteList.indexOf(to.path) !== -1) {
    //如果前往的路径是白名单内的,就可以直接前往
    next()
  } else {
    //如果路径不是白名单内的,而且又没有登录,就跳转登录页面
    next('/login')
    NProgress.done() // 结束Progress
  }
})
router.afterEach(() => {
  NProgress.done() // 结束Progress
})
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-03 16:03:16  更:2022-03-03 16:04:26 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 8:59:12-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码