<!--Shiro核心依赖-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.5.0</version>
</dependency>
Shiro功能分为认证授权 其中认证是在登录的方法中进行逻辑认证 如下:
@RequestMapping("/login")
@ResponseBody
ResultApi login(User user){
System.out.println("UserMame:-------------------"+user.getUserName());
System.out.println("PassWord:-------------------"+user.getPassWord());
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(user.getUserName(), user.getPassWord());
try{
// 开始认证,这一步会跳到我们自定义的 Realm 中
subject.login(token);
System.err.println("认证成功之后就会回到Controller层啦");
return new ResultApi(200,null,"登录成功");
}catch(Exception e){
e.printStackTrace();
System.err.println("认证失败之后也会回到Controller层啦");
return new ResultApi(200,null,"登录失败");
}
subject.login(token);底层会调用 自定义Realm中的认证方法
而授权则是在实际访问接口时触发 在自定义访问规则例如 authc需要授权访问
我的数据库表为 用户表 权限表 角色表 用户权限关联表 角色权限关联表 可以根据注释来调整自己的代码
package com.gzc.test.shiro;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.gzc.test.shiro.entity.*;
import com.gzc.test.shiro.service.*;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import javax.annotation.Resource;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class MyRealm extends AuthorizingRealm {
@Resource
private UserService userService;
@Resource
private UserRoleService userRoleService;
@Resource
private RoleService roleService;
@Resource
private RolePermissionsService rolePermissionsService;
@Resource
private PermissionsService permissionsService;
@Override //授权
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
// 获取用户名
String username = (String) principalCollection.getPrimaryPrincipal();
//根据UserName找到该用户对象
User user = userService.getOne(new QueryWrapper<User>().lambda().eq(User::getUserName, username));
System.err.println("进入自定义的Realm层的授权层了哦,并且用户名为:"+username);
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
/**
* 给该用户设置角色,角色信息存在 t_role 表中取
* authorizationInfo.setRoles(userService.getRoles(username));
*/
//1.找到该用户一共有对少角色
Set<String> roles = new HashSet<>();
//权限集合
Set<String> permissionses = new HashSet<>();
List<UserRole> userRoleList = userRoleService.list(new QueryWrapper<UserRole>().lambda().eq(UserRole::getUserId, user.getId()));
userRoleList.forEach(userRole
->
{
Role role = roleService.getOne(new QueryWrapper<Role>().lambda().eq(Role::getId, userRole.getRoleId()));
roles.add(role.getRoleName());
});
authorizationInfo.setRoles(roles);
/**
* 给该用户设置权限,权限信息存在 t_permission 表中取
* authorizationInfo.setStringPermissions(userService.getPermissions(username));
*/
userRoleList.forEach(userRole
->
{
List<RolePermissions> rolePermissionsList = rolePermissionsService.list(new QueryWrapper<RolePermissions>().lambda().eq(RolePermissions::getRoleId, userRole.getRoleId()));
rolePermissionsList.forEach(rolePermissions
->
{
Permissions permissions = permissionsService.getOne(new QueryWrapper<Permissions>().lambda().eq(Permissions::getId, rolePermissions.getPermissionsId()));
permissionses.add(permissions.getPermissionsName());
});
});
authorizationInfo.setStringPermissions(permissionses);
System.out.println("授权信息为:"+authorizationInfo);
return authorizationInfo;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
// 根据 Token 获取用户名,如果您不知道该 Token 怎么来的,先可以不管,下文会解释
String username = (String) authenticationToken.getPrincipal();
System.err.println("进入自定义的Realm层的认证层了哦,并且用户名为:"+username);
// 根据用户名从数据库中查询该用户
User user = userService.getOne(new QueryWrapper<User>().lambda().eq(User::getUserName,username));
System.err.println("该用户为"+user);
if(user != null) {
// 把当前用户存到 Session 中
SecurityUtils.getSubject().getSession().setAttribute("user", user);
// 传入用户名和密码进行身份认证,并返回认证信息
AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(user.getUserName(), user.getPassWord(), "myRealm");
System.err.println("认证信息为 :"+authcInfo);
return authcInfo;
} else {
return null;
}
}
}
配置完ShiroConfig就可以进行测试了 我这里用的是注解的方法 之前我因为少两个方法导致访问注解下的方法不触发权限验证 具体代码的方法我在下方写出 遇到这个问题的小伙伴可以参考一下
DefaultAdvisorAutoProxyCreator方法
AuthorizationAttributeSourceAdvisor方法
方法内容下方的代码块中有 这里只是单独罗列出来
package com.gzc.test.shiro;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
private static final Logger logger = LoggerFactory.getLogger(ShiroConfig.class);
/**
* 注入自定义的 Realm
* @return MyRealm
*/
@Bean
public MyRealm myAuthRealm() {
MyRealm myRealm = new MyRealm();
logger.info("====myRealm注册完成=====");
return myRealm;
}
@Bean
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
return advisorAutoProxyCreator;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
/**
* 注入安全管理器
* @return SecurityManager
*/
@Bean
public DefaultWebSecurityManager securityManager() {
// 将自定义 Realm 加进来
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(myAuthRealm());
logger.info("====securityManager注册完成====");
return securityManager;
// return null;
}
/**
* 注入 Shiro 过滤器
* @param securityManager 安全管理器
* @return ShiroFilterFactoryBean // SecurityManager securityManager
*/
@Bean
public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) {
// 定义 shiroFactoryBean
ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
// 设置自定义的 securityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 设置默认登录的 URL,身份认证失败会访问该 URL
shiroFilterFactoryBean.setLoginUrl("/login");
// 设置成功之后要跳转的链接
shiroFilterFactoryBean.setSuccessUrl("/success");
// 设置未授权界面,权限认证失败会访问该 URL
shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");
// LinkedHashMap 是有序的,进行顺序拦截器配置
Map<String,String> filterChainMap = new LinkedHashMap<>();
// 配置可以匿名访问的地址,可以根据实际情况自己添加,放行一些静态资源等,anon 表示放行
filterChainMap.put("/css/**", "anon");
filterChainMap.put("/imgs/**", "anon");
filterChainMap.put("/js/**", "anon");
filterChainMap.put("/swagger-*/**", "anon");
filterChainMap.put("/swagger-ui.html/**", "anon");
// 登录 URL 放行
filterChainMap.put("/login", "anon");
// 以“/user/admin” 开头的用户需要身份认证,authc 表示要进行身份认证
filterChainMap.put("/user/*", "authc");
// “/user/student” 开头的用户需要角色认证,是“admin”才允许
filterChainMap.put("/user/student*/**", "roles[admin]");
// “/user/teacher” 开头的用户需要权限认证,是“user:create”才允许
filterChainMap.put("/user/teacher*/**", "perms[\"user:create\"]");
// 配置 logout 过滤器
filterChainMap.put("/logout", "logout");
// 设置 shiroFilterFactoryBean 的 FilterChainDefinitionMap
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainMap);
logger.info("====shiroFilterFactoryBean注册完成====");
return shiroFilterFactoryBean;
}
}
@RequestMapping("/user/testPermission")
@ResponseBody
@RequiresRoles("student")
ResultApi testPermissiom(){
System.out.println("访问成功");
return null;
}
因为我在上方配置了访问路径/user/*下需要权限验证 @RequiresRoles(“权限名称”)注解为需要此权限才能访问
在没有权限的情况下会报一个异常 如下
这个其实他不影响正常使用 但是 想处理的小伙伴可以写一个全局异常捕获 代码如下:
package com.gzc.test.utils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authz.AuthorizationException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class ExceptionsHandler {
//对没权限的进行结果进行拦截
@ExceptionHandler(AuthorizationException.class)
public ResultApi authorizationExceptionHandler(AuthorizationException authorizationException) {
return new ResultApi(403,null,"没有访问权限");
}
}
之后就可以再次重启访问 再次测试了