用户授权

用户授权业务流程

在这里插入图片描述

  • 业务流程说明
    • (1)用户认证通过,认证服务向浏览器cookie写入token(身份令牌)
    • (2)前端携带token请求用户中心服务获取jwt令牌
      • 前端获取到jwt令牌解析,并存储在sessionStorage
    • (3)前端携带cookie中的身份令牌及jwt令牌访问资源服务
      • 前端请求资源服务需要携带两个token:一个是cookie中的身份令牌,一个是http header中的jwt
      • 前端请求资源服务前在http header上添加jwt请求资源
    • 网关验证token的合法性
      • 用户请求必须携带身份令牌和jwt令牌
      • 网关校验redis中user_token的有效期,已过期则要求用户重新登录
    • 资源服务校验jwt的合法性并进行授权
      • 资源服务校验jwt令牌,完成授权,拥有权限的方法正向执行,没有权限的方法拒绝访问。

方法授权

需求分析

  • 生成jwt令牌时动态查询用户拥有的权限
    • 管理员给用户分配权限,权限数据写到数据库中。
    • 、认证服务在进行用户认证时从数据库读取用户的权限数据(动态数据)
  • 资源服务方法添加注解PreAuthorize,指定方法所需要的权限
    • 示例
    @PreAuthorize("hasAuthority('course_find_list')")
    @Override
    public QueryResult<CourseInfo> findCourseList(@PathVariable("page") int page,
    @PathVariable("size") int size,	CourseListRequest courseListRequest)
    
  • 当请求有权限的方法时正常访问
  • 当请求没有权限的方法时拒绝访问

jwt令牌包含权限

  • 修改认证服务的UserDetailServiceImpl类
  • 将权限标识按照中间使用逗号分隔的语法组成一个字符串,最终提供给Spring security。
    //指定用户的权限,这里暂时硬编码
   List<String> permissionList = new ArrayList<>();
   permissionList.add("course_get_baseinfo");
   permissionList.add("course_find_pic");
   //将权限串中间以逗号分隔
   String permissionString = StringUtils.join(permissionList.toArray(), ",");
   //String user_permission_string = "";
   UserJwt userDetails = new UserJwt(username,
   password,AuthorityUtils.commaSeparatedStringToAuthorityList(permissionString));

方法授权实现

  • 资源服务添加授权控制
    • 添加spring-cloud-starter-oauth2依赖。
    • 拷贝授权配置类ResourceServerConfig。
    • 拷贝公钥。
  • 方法添加注解
    • 在资源服务的controller方法时会使用注解指定此方法的权限标识。
    • 在资源服务(这里是课程管理)的ResourceServerConfig类上添加注解,激活方法上添加授权注解。
    	//激活方法上的PreAuthorize注解
     @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
    

细粒度授权

分析

  • 细粒度授权也叫数据范围授权,即不同的用户所拥有的操作权限相同,但是能够操作的数据范围是不一样的。

实现

  • 细粒度授权涉及到不同的业务逻辑,通常在service层实现,根据不同的用户进行校验,根据不同的参数查询不同的数据或操作不同的数据。
  • 获取当前用户信息
    • 认证服务在用户认证通过将用户需要的信息存储到jwt令牌中。
    • 用户请求到达资源服务后,资源服务需要取出header中的jwt令牌,并解析出用户信息。
  • JWT解析工具类
	public class Oauth2Util {
		public static Map<String,String> getJwtClaimsFromHeader(HttpServletRequest request) {
		if (request == null) {
			return null;
		}
		//取出头信息
		String authorization = request.getHeader("Authorization");
		if (StringUtils.isEmpty(authorization) || authorization.indexOf("Bearer") < 0) {
			return null;
		}
		//从Bearer 后边开始取出token
		String token = authorization.substring(7);
		Map<String,String> map = null;
		try {
			//解析jwt
			Jwt decode = JwtHelper.decode(token);
			//得到 jwt中的用户信息
			String claims = decode.getClaims();
			//将jwt转为Map
			map = JSON.parseObject(claims, Map.class);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return map;
		}
	}

微服务之间认证

分析

  • 用户携带身份令牌和JWT令牌访问微服务,微服务获取jwt并完成授权。
  • 当微服务访问微服务,此时如果没有携带JWT则微服务会在授权时报错。

Feign拦截

  • 定义Feign拦截器
    • 微服务之间使用feign进行远程调用,采用feign拦截器实现远程调用携带JWT。
    public class FeignClientInterceptor implements RequestInterceptor {
    @Override
    	public void apply(RequestTemplate requestTemplate) {
    		try {
    			//使用RequestContextHolder工具获取request相关变量
    			ServletRequestAttributes attributes = (ServletRequestAttributes)
    			RequestContextHolder.getRequestAttributes();
    			if(attributes!=null){
    			//取出request
    			HttpServletRequest request = attributes.getRequest();
    			Enumeration<String> headerNames = request.getHeaderNames();
    			if (headerNames != null) {
    				while (headerNames.hasMoreElements()) {
    					String name = headerNames.nextElement();
    					String values = request.getHeader(name);
    					if(name.equals("authorization")){
    					//System.out.println("name="+name+"values="+values);
    						requestTemplate.header(name, values);
    					}
    				}
    			}
    		}
    		}catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }
    
    • 使用Feign拦截,在启动类中定义bean
    @Bean
    public FeignClientInterceptor feignClientInterceptor(){
    	return new FeignClientInterceptor();
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值