前言
上边分享如何实现网关鉴权介绍,那么问题来了,所有用户进来可以是不同的角色,不同的权限,这里后端怎么控制呢。
方法授权
需求分析
方法授权要完成的是provider
访问根据jwt令牌完成对方法的授权,具体流程如下:
- 生成Jwt令牌时在令牌中写入用户所拥有的权限我们给每个权限起个名字,例如某个用户拥有如下权限:
batman:访问provider
的hello
接口 - 在
hello
方法上添加注解PreAuthorize
,并指定此方法所需要的权限,它就表示要执行这个方法需要拥有batman权限。hello2
表示要拥有batman2
权限才能访问。
@Override
@PreAuthorize("hasAuthority('batman')")
public String hello() {
return "hello world oauth2";
}
@Override
@PreAuthorize("hasAuthority('batman2')")
public String hello2() {
return "hello world oauth2";
}
- 当请求有权限的方法时正常访问
- 当请求没有权限的方法时则拒绝访问
jwt令牌包含权限
修改provider
服务的UserDetailServiceImpl
类,下边的代码中 permissionList
列表中存放了用户的权限,并且将权限标识按照中间使用逗号分隔的语法组成一个字符串,最终提供给Spring security。(这里将权限写死了,大家可以遵循RABC
原则建关系表,从数据库中查询角色权限)
//TODO从数据库获取权限
List<FooMenu> permissions = userext.getPermissions();
List<String> user_permission = new ArrayList<>();
permissions.forEach(item -> user_permission.add(item.getCode()));
user_permission.add("batman");
String user_permission_string = StringUtils.join(user_permission.toArray(), ",");
方法授权测试
重启
provider
服务,使用postman测试,GET 请求http://batman.com:18085/security-provider/security/hello
,注意加上Authorization
GET 请求
http://batman.com:18085/security-provider/security/hello2
小结
- ResourceServerConfig类上添加注解,如下:
//激活方法上的PreAuthorize注解
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
- 在方法添加授权注解
@PreAuthorize("hasAuthority('???')")
- 如果方法上不添加授权注解表示此方法不需要权限即可访问。
服务token传递
定义Feign拦截器
微服务之间使用feign进行远程调用,采用feign拦截器实现远程调用携带JWT。
创建
FeignClientInterceptor
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();
}
}
}
注入到spring容器
@Bean
public FeignClientInterceptor feignClientInterceptor() {
return new FeignClientInterceptor();
}