欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

SpringBoot———@注解

程序员文章站 2022-07-14 15:32:31
...

可先阅读:Java基础加强总结(一)——注解(Annotation)

举个栗子

通过自定义注解来做角色权限控制

1.首先我们新建一个注解@PermInfo 

import java.lang.annotation.*;

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PermInfo {

    /**
     * 权限值
     * @return
     */
    String pval() default "";

    /**
     * 权限名称
     * pname的别名
     * @return
     */
    String value() default "";

}

2.在相关controller层加上该注解

 @PermInfo("查询所有产品")
public Json queryProduct(@RequestBody String body) {

}

角色添加完毕。

实用技能之角色权限验证

先来看用法(Springboot+vue-elelment实现的前后端分离):

1.前端用法

//router.js(路由配置,根据角色显示不同的菜单栏内容)————建议m:开头
//角色控制(将内容绑定给角色)
export const asyncRouterMap = [

  {
    path: '/product',
    component: Layout,
    meta: { perm:'m:product', title: 'product', icon: 'product' },
    children: [
      {
        path: 'prod_manage',
        name: 'prod_manage',
        component: _import('product/product'),
        meta: { perm: 'm:product', title: 'product', icon: 'product', noCache: true }
      },
    ]}
]
//view.vue 页面元素设置权限————建议b:开头
//查询按钮授予查询权限
<el-button icon="el-icon-search" circle @click="handleQuery()" v-perm="'b:prod:query'"></el-button>

2.后端用法

//定义接口权限 ————建议a:开头   
@PermInfo("查询所有产品")
    @RequiresPermissions("a:prod:query")
    @RequestMapping(value = "/query", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
    public Json queryProduct(@RequestBody String body) {
        //...
}

那么怎么配置呢?

其实在首后端使用Shiro框架处理即可

1.首先新准备好UserRelam.java (主要是自定义了如何查询用户信息,如何查询用户的角色和权限,如何校验密码等逻辑)

package com.finshell.uniocredit.shiro;


import com.finshell.uniocredit.entity.SysUser;
import com.finshell.uniocredit.service.SysPermService;
import com.finshell.uniocredit.service.SysRoleService;
import com.finshell.uniocredit.service.SysUserService;
import com.finshell.uniocredit.vo.AuthVo;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Set;
import java.util.stream.Collectors;

/**
 * 这个类是参照JDBCRealm写的,主要是自定义了如何查询用户信息,如何查询用户的角色和权限,如何校验密码等逻辑
 */
public class UserRealm extends AuthorizingRealm {

    private static final Logger log =LoggerFactory.getLogger(UserRealm.class);

    @Autowired
    private SysUserService userService;
    @Autowired
    private SysRoleService roleService;
    @Autowired
    private SysPermService permService;

    //密码匹配
    @Override
    public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
        //设置用于匹配密码的CredentialsMatcher
        HashedCredentialsMatcher hashMatcher = new HashedCredentialsMatcher();
        hashMatcher.setHashAlgorithmName(Sha256Hash.ALGORITHM_NAME);
        hashMatcher.setStoredCredentialsHexEncoded(false);
        hashMatcher.setHashIterations(1024);
        super.setCredentialsMatcher(hashMatcher);
    }

    //权限认证
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //null usernames are invalid
        if (principals == null) {
            throw new AuthorizationException("PrincipalCollection method argument cannot be null.");
        }

        SysUser user = (SysUser) getAvailablePrincipal(principals);
        Set<AuthVo> roles = user.getRoles();
        Set<AuthVo> perms = user.getPerms();
        log.info("获取角色权限信息: roles: {}, perms: {}",roles,perms);

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setRoles(roles.stream().map(AuthVo::getVal).collect(Collectors.toSet()));
        info.setStringPermissions(perms.stream().map(AuthVo::getVal).collect(Collectors.toSet()));
        return info;
    }

    //身份认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        UsernamePasswordToken upToken = (UsernamePasswordToken) token;
        String username = upToken.getUsername();

        if (username == null) {
            throw new AccountException("用户名不能为空");
        }

        SysUser userDB = userService.selectOne(new EntityWrapper<SysUser>().eq("uname", username));
        if (userDB == null) {
            throw new UnknownAccountException("找不到用户("+username+")的帐号信息");
        }

        //查询用户的角色和权限存到SimpleAuthenticationInfo中,这样在其它地方
        //SecurityUtils.getSubject().getPrincipal()就能拿出用户的所有信息,包括角色和权限
        Set<AuthVo> roles = roleService.getRolesByUserId(userDB.getUid());
        Set<AuthVo> perms = permService.getPermsByUserId(userDB.getUid());
        userDB.getRoles().addAll(roles);
        userDB.getPerms().addAll(perms);

        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(userDB, userDB.getPwd(), getName());
        if (userDB.getSalt() != null) {
            info.setCredentialsSalt(ByteSource.Util.bytes(userDB.getSalt()));
        }
        return info;
    }
}

2.配置ShiroConfig.java (以@Configratio的方式)

package com.finshell.uniocredit.config;

import com.finshell.uniocredit.shiro.UserRealm;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ShiroConfig {

    @Bean
    public Realm realm() {
        return new UserRealm();
    }

    @Bean
    public static DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
        /**
         * setUsePrefix(false)用于解决一个奇怪的bug。在引入spring aop的情况下。
         * 在@Controller注解的类的方法中加入@RequiresRole注解,会导致该方法无法映射请求,导致返回404。
         * 加入这项配置能解决这个bug
         */
        creator.setUsePrefix(true);
        return creator;
    }

    /**
     * 这里统一做鉴权,即判断哪些请求路径需要用户登录,哪些请求路径不需要用户登录。
     * 这里只做鉴权,不做权限控制,因为权限用注解来做。
     * @return
     */
    @Bean
    public ShiroFilterChainDefinition shiroFilterChainDefinition() {
        DefaultShiroFilterChainDefinition chain = new DefaultShiroFilterChainDefinition();
        //哪些请求可以匿名访问
        chain.addPathDefinition("/auth/login", "anon");
        chain.addPathDefinition("/auth/logout", "anon");
        chain.addPathDefinition("/page/401", "anon");
        chain.addPathDefinition("/page/403", "anon");
        chain.addPathDefinition("/page/index", "anon");
        chain.addPathDefinition("/basic/product", "anon");


        //除了以上的请求外,其它请求都需要登录
        chain.addPathDefinition("/**", "authc");
        return chain;
    }
}

3.application-shiro.yml配置

shiro:
  loginUrl: /auth/page/401
  unauthorizedUrl: /auth/page/403
  successUrl: /auth/page/index

结合以下材料会更好理解:

1. springboot整合shiro-SimpleAuthenticationInfo 参数该使用username 还是User实体(十八)

2. 部分注解解释

3. SpringBoot+Shiro学习之数据库动态权限管理和Redis缓存