简单的权限验证

登录与授权

前言:如果采用spring家族进行后端开发,想要实现多用户多权限很容易联想到spring security,shiro两大常见框架,但是两者都有一定的学习成本,并且由于兼容了很多设计模式的思想,源码很复杂,短时间不容易上手。那么,我们能不能通过一些java基础知识实现呢?因此本文使用注解+拦截器实现多用户多权限功能。

多用户是什么?比如,课堂中有授课的老师,听课的学生,这就是两种类型的用户。

多权限是什么?老师拥有授课权限,学生具有听课权限。非学生无听课权限,非老师无授课权限,如学生无授课权限。

在这里插入图片描述

构建一个基本的多用户多权限应用场景,学生和教师可进入学校,教师可授课,学生可听课。在生活中是怎么实现的呢?门卫大叔查看你的学生或教师信息确认为本校人员,学生通过课程表进入可进入的教室听课,非课程表内的教室为其他用户占用,教师同理。

在这里插入图片描述

观察得,多用户多权限系统需要一个门卫查岗的系统,进入系统后用户根据用户身份拥有不同权限。那么我们怎么用java程序实现呢?我们可选择使用拦截器拦截除登录外的所有访问系统的路劲,实现“查岗”即登录操作。用户登录后我们返回前端一个标识用户的信息字段“token”字段,用户访问非登录路径时携带token字段,通过拦截器我们可以解析token获取用户拥有的权限,在访问具体的路径方法时,我们可以通过注解配置访问该路径方法需要的权限。如此便实现多用户多权限登录。

以下是结合代码进行实战:

我们先整理好一个开发的思路,首先是使用springboot进行开发,使用jwt加密传递的token字段,使用redis缓存不同的token键对应的用户信息值。使用拦截器拦截非登录方法,拦截时获取用户的权限,访问方法时通过注解获取方法需要的用户权限进行校验。

实现作用:使用用户类型标识用户权限,一个路径方法可配置多用户访问,用户可有多角色,用户拥有其中一种角色即可。适用于粗粒度系统。

注解

  • 登录注解

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE, ElementType.METHOD})
    public @interface LoginRequired {
    }
    
  • 鉴权注解

    @LoginRequired//使用了登录注解,先登录再鉴权
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE, ElementType.METHOD})
    public @interface PermissionRequired {
        /**
         * 角色,默认游客权限
         *
         * @return
         */
        UserType[] userType() default {UserType.VISITOR};
    }
    

token

使用token时,可以使用jwt进行加密传输,同时可以在服务度对jwt进行加盐

//存入
String token = JwtUtil.createJWT("标识字段");    
redisCache.setCacheObject("盐"+"标识字段",user);
return token;
//取出
 标识字段 = JwtUtil.parseJWT(token).getSubject();
 User user = redisCache.getCacheObject("盐"+"标识字段");

易错点

注入拦截器到spring容器中,不注意的话,很容易犯下关于redistemplete的空指针异常。原因是拦截器是最先执行的,此时未初始化bean,因此在拦截类使用的redistemplete此时为空。

如,此时在拦截器内不能使用任何bean

@Configuration
public class MvcConfig implements WebMvcConfigurer {
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/**");
    }
}

推荐写法为

@Configuration
public class MvcConfig implements WebMvcConfigurer {

    @Bean
    public LoginInterceptor getLoginInterceptor(){
        return new LoginInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(getLoginInterceptor())
                .addPathPatterns("/**")
        .excludePathPatterns("/login");
    }
}

还有一些比较基础的代码不在此阐述,比如在拦截器中查询用户的用户角色并缓存在redis中,并且校验。

下面的云盘包含所有代码以及sql,仅供参考。项目中采用的微信登录,读者可更改使用即可,不影响系统功能的完整性。

链接:https://pan.baidu.com/s/1mfBJioyA5C7pVAIYE3fLSw?pwd=wang
提取码:wang

本文参考了众多博客的思路,如侵权,请您联系。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Shiro 是一个强大的 Java 安全框架,提供了身份认证、授权、加密等功能。以下是一个简单的 Shiro 权限验证代码示例: 1. 配置 Shiro 安全管理器 ```java // 创建一个 DefaultSecurityManager 对象 DefaultSecurityManager securityManager = new DefaultSecurityManager(); // 设置 Realm securityManager.setRealm(myRealm); // 将 SecurityManager 设置为全局的安全管理器 SecurityUtils.setSecurityManager(securityManager); ``` 2. 创建一个自定义 Realm 类 ```java public class MyRealm extends AuthorizingRealm { // 授权方法 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { // 获取当前用户 String username = (String) principals.getPrimaryPrincipal(); // 根据用户名查询该用户的角色和权限 Set<String> roles = userService.findRolesByUsername(username); Set<String> permissions = userService.findPermissionsByUsername(username); // 创建 SimpleAuthorizationInfo 对象,并设置角色和权限 SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); authorizationInfo.setRoles(roles); authorizationInfo.setStringPermissions(permissions); return authorizationInfo; } // 认证方法 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { // 获取用户名和密码 String username = (String) token.getPrincipal(); String password = new String((char[]) token.getCredentials()); // 查询用户是否存在 User user = userService.findByUsername(username); if (user == null) { throw new UnknownAccountException("用户不存在"); } // 验证密码 if (!passwordEncoder.matches(password, user.getPassword())) { throw new IncorrectCredentialsException("密码错误"); } // 创建 SimpleAuthenticationInfo 对象,并设置用户名和密码 SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username, password, getName()); return authenticationInfo; } } ``` 3. 在 Controller 中进行权限验证 ```java @Controller public class UserController { @RequiresPermissions("user:list") @GetMapping("/user/list") public String list() { // 用户列表页面 return "user/list"; } @RequiresPermissions("user:add") @GetMapping("/user/add") public String add() { // 添加用户页面 return "user/add"; } @RequiresPermissions("user:edit") @GetMapping("/user/edit") public String edit() { // 编辑用户页面 return "user/edit"; } } ``` 在上述代码中,@RequiresPermissions 注解表示该方法需要进行权限验证。如果当前用户拥有对应的权限,则可以访问该方法;否则将抛出 UnauthorizedException 异常。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值