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. 部分注解解释