赞
踩
目录
RBAC基本思想是,对系统操作的各种权限不是直接授予具体的用户,而是在用户集合与权限集合之间建立一个角色集合。每一种角色对应一组相应的权限。一旦用户被分配了适当的角色后,该用户就拥有此角色的所有操作权限。这样做的好处是,不必在每次创建用户时都进行分配权限的操作,只要分配用户相应的角色即可,而且角色的权限变更比用户的权限变更要少得多,这样将简化用户的权限管理,减少系统的开销。
Springboot+AOP切面+自定义注解+redis+jwt+mybatis+token拦截器
注:为了简化操作和流程,没有真正地从mysql中读取数据,而是以写死的数据进行演示
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- <version>1.16.12</version>
- </dependency>
- <dependency>
- <groupId>org.aspectj</groupId>
- <artifactId>aspectjrt</artifactId>
- <version>1.8.9</version>
- </dependency>
- <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjtools -->
- <dependency>
- <groupId>org.aspectj</groupId>
- <artifactId>aspectjtools</artifactId>
- <version>1.8.9</version>
- </dependency>
- <dependency>
- <groupId>org.aspectj</groupId>
- <artifactId>aspectjweaver</artifactId>
- <version>1.7.4</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-redis</artifactId>
- </dependency>
- <!--hutool-->
- <dependency>
- <groupId>cn.hutool</groupId>
- <artifactId>hutool-all</artifactId>
- <version>5.7.17</version>
- </dependency>
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>fastjson</artifactId>
- <version>1.2.62</version>
- </dependency>
- <!--hutool-->
- <dependency>
- <groupId>cn.hutool</groupId>
- <artifactId>hutool-all</artifactId>
- <version>5.7.17</version>
- </dependency>

- package com.melody.rest.restcontroller;
-
- import com.melody.rest.domain.RestSysUser;
- import com.melody.rest.model.ResultJson;
- import com.melody.rest.service.RestAuthService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.PostMapping;
- import org.springframework.web.bind.annotation.RequestBody;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RestController;
-
- @RestController
- @RequestMapping("/rest")
- public class LoginController {
-
- @Autowired
- private RestAuthService restAuthService;
-
-
- //登录
- @PostMapping("/login")
- public ResultJson index(@RequestBody RestSysUser restSysUser){
- //登录以及登录成功存入token
- return restAuthService.Login(restSysUser);
- }
-
- }

- package com.melody.rest.service;
-
-
- import com.melody.rest.domain.RestSysUser;
- import com.melody.rest.model.ResultJson;
-
- public interface RestAuthService {
-
- //登录方法
- ResultJson Login(RestSysUser restSysUser);
-
-
- }
在业务中判断账号密码的正确性,并将用户账户、密码、token存入redis,设置token一天有效期
- package com.melody.rest.service.impl;
-
-
- import cn.hutool.core.bean.BeanUtil;
- import cn.hutool.core.bean.copier.CopyOptions;
- import com.melody.rest.domain.RestSysUser;
- import com.melody.rest.model.ResultCode;
- import com.melody.rest.model.ResultJson;
- import com.melody.rest.service.RestAuthService;
- import com.melody.rest.util.ResourceVerification;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.data.redis.core.RedisTemplate;
- import org.springframework.stereotype.Service;
-
-
- import java.util.HashMap;
- import java.util.Map;
- import java.util.UUID;
- import java.util.concurrent.TimeUnit;
-
-
- @Service
- public class RestAuthServiceImpl implements RestAuthService {
-
- @Autowired
- RedisTemplate redisTemplate;
-
-
- @Override
- public ResultJson Login(RestSysUser restSysUser) {
- //账号密码校验,
- if("admin".equals(restSysUser.getUsername()) && "123456".equals(restSysUser.getPassword())){
- //账号密码正确
- restSysUser.setResources(ResourceVerification.resource());//向用户权限中注入写死的权限
- Map<String, Object> userMap = BeanUtil.beanToMap(restSysUser, new HashMap<>(),
- CopyOptions.create()
- .setIgnoreNullValue(true)//忽略一些空值
- .setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString()));
- UUID uuid = UUID.randomUUID();
- String tokenKey= String.valueOf(uuid);
- String token="LoginUserKey "+tokenKey;
- //存储
- redisTemplate.opsForHash().putAll(token,userMap);
- //设置存值时间,expire默认秒,改为天数,设置1天
- redisTemplate.expire(token,1, TimeUnit.DAYS);
- return ResultJson.ok(token);
- }else{
- //账号密码不正确
- return ResultJson.failure(ResultCode.LOGIN_ERROR);
- }
- }
- }

测试用的权限:
拦截器不受spring管理,因此需要在拦截器中注入redis模板类RedisTemplate,使用有参构造将RedisTemplate传递给token拦截类
- package com.melody.rest.config;
-
- import com.melody.rest.util.LoginInterceptor;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.data.redis.core.RedisTemplate;
- import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
- import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
-
-
- import javax.annotation.Resource;
-
- @Configuration
- public class MvcConfig implements WebMvcConfigurer {
-
- @Resource
- RedisTemplate redisTemplate;
-
- @Override
- public void addInterceptors(InterceptorRegistry registry) {
-
- //配置登录查看是否有token拦截器
- registry.addInterceptor(new LoginInterceptor(redisTemplate)).addPathPatterns("/testRest/**").order(0);
-
- }
- }

- package com.melody.rest.util;
-
-
- import cn.hutool.core.bean.BeanUtil;
- import com.alibaba.fastjson.JSONObject;
- import com.melody.rest.domain.RestData;
- import com.melody.rest.domain.RestSysUser;
- import org.springframework.data.redis.core.RedisTemplate;
- import org.springframework.web.servlet.HandlerInterceptor;
-
-
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import java.util.Map;
-
- public class LoginInterceptor implements HandlerInterceptor {
-
- private RedisTemplate redisTemplate;
-
- public LoginInterceptor(RedisTemplate redisTemplate){
- this.redisTemplate=redisTemplate;
- }
-
-
- @Override
- public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
-
- //设置编码
- response.setCharacterEncoding("utf-8");
- response.setContentType("text/json;charset=utf-8");
-
- //1、判断是否携带token
- String token = request.getHeader("authorization");
- if(token==null || "".equals(token)){
- RestData restData = RestData.builder().code("401").msg("请先登录再操作!").build();
- String jsonRestData = JSONObject.toJSONString(restData);
- response.setStatus(401);
- response.getWriter().write(jsonRestData);
- return false;
- }
- Map<String, Object> userMap=redisTemplate.opsForHash().entries(token);
- RestSysUser restSysUser = BeanUtil.fillBeanWithMap(userMap, new RestSysUser(), false);
- //2、判断redis里面是否存在token
- if(userMap.isEmpty()){
- RestData restData = RestData.builder().code("401").msg("请先登录再操作!").build();
- String jsonRestData = JSONObject.toJSONString(restData);
- response.setStatus(401);
- response.getWriter().write(jsonRestData);
- return false;
- }
-
- return true;
- }
- }

- package com.melody.rest.annotion;
-
- import java.lang.annotation.*;
-
- @Target({ ElementType.PARAMETER, ElementType.METHOD })
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- public @interface AuthCheck {
-
- public String value() default "";
-
- }
- package com.melody.rest.aspect;
-
-
- import cn.hutool.core.bean.BeanUtil;
- import com.melody.rest.annotion.AuthCheck;
- import com.melody.rest.domain.RestSysUser;
- import com.melody.rest.exception.AuthException;
- import com.melody.rest.model.ResCode;
- import com.melody.rest.model.ResJson;
- import com.melody.rest.model.ResultCode;
- import com.melody.rest.model.ResultJson;
- import org.aspectj.lang.ProceedingJoinPoint;
- import org.aspectj.lang.annotation.Around;
- import org.aspectj.lang.annotation.Aspect;
- import org.aspectj.lang.annotation.Pointcut;
- import org.aspectj.lang.reflect.MethodSignature;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.data.redis.core.RedisTemplate;
- import org.springframework.stereotype.Component;
-
-
- import javax.annotation.Resource;
- import javax.servlet.http.HttpServletRequest;
- import java.lang.reflect.Method;
- import java.util.Map;
-
- @Aspect
- @Component
- public class AuthAspect {
-
- @Value("${token.header}")
- private String header;
-
- @Autowired
- private HttpServletRequest request;
-
- @Resource
- private RedisTemplate redisTemplate;
-
- @Pointcut("@annotation(com.melody.rest.annotion.AuthCheck)")
- public void authPointCut(){
-
- }
-
-
- @Around("authPointCut()")
- public Object authCheck(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
- try{
- // 判断 TOKEN
- String token = request.getHeader(header);
- System.err.println(token);
- Map<String, Object> userMap=redisTemplate.opsForHash().entries(token);
- RestSysUser restSysUser = BeanUtil.fillBeanWithMap(userMap, new RestSysUser(), false);
- if(restSysUser.getUsername() == null || restSysUser.getUsername().equals("")){
- throw new AuthException(ResCode.TOKEN_NOT_EXIST);
- } else {
- if(restSysUser.getResources()==null){
- throw new AuthException(ResCode.BANED_REQUEST);
- }
- //从切面织入点处通过反射机制获取织入点处的方法
- MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
- //获取切入点所在的方法
- Method method = signature.getMethod();
- AuthCheck ac = method.getAnnotation(AuthCheck.class);
- // System.err.println("=========================="+ac);
- boolean flag = false;
- if(ac != null) {
- //获取切入点方法的value值,该测试接口设置的value为权限字段
- String auth = ac.value();
- // System.err.println("-----------------------------"+auth);
- flag = restSysUser.getResources().stream().anyMatch(str -> str.equals(auth));
- // way2:数据库中存放权限字段,根据注解的value确定请求所需权限判断是否有权限进行访问
- }
- if(!flag) {
- return ResultJson.failure(ResultCode.FORBIDDEN);
- }
- }
- } catch(AuthException e) {
- System.err.println(e.getResCode().getCode() + ":" + e.getResCode().getMsg());
- return ResJson.no(e.getResCode());
- }
- // Object res = proceedingJoinPoint.proceed();
- return proceedingJoinPoint.proceed();
- }
-
- }

- package com.melody.rest.restcontroller;
-
- import com.melody.rest.annotion.AuthCheck;
- import com.melody.rest.model.ResultJson;
- import org.springframework.web.bind.annotation.PostMapping;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RestController;
-
-
-
- @RestController
- @RequestMapping("/testRest")
- public class TestRestController {
-
-
-
- //测试方法1
- @AuthCheck("/testRest/t1")
- @PostMapping("/t1")
- public ResultJson test(){
- return ResultJson.ok("test1访问成功");
- }
-
- //测试方法2
- @AuthCheck("/testRest/t10")
- @PostMapping("/t10")
- public ResultJson test2(){
- return ResultJson.ok("test10访问");
- }
-
- }

在写死的权限中只有test1、2、3的权限,而方法二权限为test10
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。