导入依赖
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.0</version> </dependency>
配置安全管理器
/** * @Description:shiro配置 * @author Chen * @create 2019-07-07 20:02 */ @Configuration public class ShiroConfig { /** * 创建ShiroFilterFactoryBean */ @Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){ ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); //设置安全管理器 shiroFilterFactoryBean.setSecurityManager(securityManager); // setLoginUrl 如果不设置值,默认会自动寻找Web工程根目录下的"/login.jsp"页面 或 "/login" 映射 shiroFilterFactoryBean.setLoginUrl("/notLogin"); //添加Shiro内置过滤器 /** * Shiro内置过滤器,可以实现权限相关的拦截器 * 常用的过滤器: * anon: 无需认证(登录)可以访问 * authc: 必须认证才可以访问 * user: 如果使用rememberMe的功能可以直接访问 * perms: 该资源必须得到资源权限才可以访问 * role: 该资源必须得到角色权限才可以访问 */ Map<String,String> map = new LinkedHashMap<String, String>(); map.put("/adminLogin","anon"); map.put("/swagger-ui.html", "anon"); map.put("/swagger-resources", "anon"); map.put("/v2/api-docs", "anon"); map.put("/webjars/springfox-swagger-ui/**", "anon"); map.put("/*","authc"); shiroFilterFactoryBean.setFilterChainDefinitionMap(map); return shiroFilterFactoryBean; } /** * 创建DefaultWebSecurityManager * @return */ @Bean("securityManager") public DefaultWebSecurityManager getDefaultWebSecurityManager(){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); //关联UserRealm securityManager.setRealm(getUserRealm()); return securityManager; } /** * 创建realm * @return */ @Bean("userRealm") public UserRealm getUserRealm(){ return new UserRealm(); } @Bean(name="lifecycleBeanPostProcessor") public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } /** * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证 * 配置以下两个bean(DefaultAdvisorAutoProxyCreator(可选)和AuthorizationAttributeSourceAdvisor)即可实现此功能 * * @return */ @Bean @DependsOn({"lifecycleBeanPostProcessor"}) public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); advisorAutoProxyCreator.setProxyTargetClass(true); return advisorAutoProxyCreator; } @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(getDefaultWebSecurityManager()); return authorizationAttributeSourceAdvisor; } }
配置Realm
/** * @Description:Realm配置 * @author Chen * @create 2019-07-07 20:02 */ public class UserRealm extends AuthorizingRealm { @Autowired private IUserService userService; @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { System.out.println("执行授权"); String uEmail = (String) principalCollection.getPrimaryPrincipal(); User user = userService.getByEmail(uEmail); List<String> permissions = new ArrayList<String>(); List<String> roles = new ArrayList<String>(); if ("admin".equals(uEmail)) { //让超级管理员拥有所有权限 permissions.add("*:*"); } else { //根据用户ID查询该用户具有的角色 roles = userService.getRoleByUserId(user.getuId()); //根据用户ID查询该用户具有的权限 permissions = userService.getPermissionByUserId(user.getuId()); if (permissions.get(0) == null){ throw new MyException(400,"无权限"); } } SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.addStringPermissions(permissions); info.addRoles(roles); return info; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { System.out.println("··········执行认证逻辑··········"); //转为UsernamePasswordToken UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; User user = userService.getByEmail(token.getUsername()); //判断用户名 if (user == null) { //用户名不存在 //Shiro底层会抛出异常 return null; } //判断密码 return new SimpleAuthenticationInfo(user.getuEmail(), user.getuPassword(), ""); } }
认证
@PostMapping("/adminLogin") public Responsive adminLogin(@RequestBody AdminLoginReq adminLoginReq) { //1.获取subject Subject subject = SecurityUtils.getSubject(); //2.封装用户数据 UsernamePasswordToken token = new UsernamePasswordToken(adminLoginReq.getUEmail(), adminLoginReq.getUPassword()); //3.执行登录方法 try { subject.login(token); //登录成功 return Responsive.success(); } catch (UnknownAccountException e) { //用户名不存在 return Responsive.of(400, "用户名或密码错误"); } catch (IncorrectCredentialsException e) { //密码错误 return Responsive.of(400, "用户名或密码错误"); } }
授权
使用注解即可实现权限控制:
@RequiresPermissions("需要的权限")
@RequiresRoles("需要的角色")
@PermissionName(“自定义注解用于获取权限名称信息”)
加载权限到数据库:
/** * @author Chen * @Description 自定义注解 用于获取权限名称 * @create 2019-07-08 13:13 */ @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface PermissionName { String value(); }
/** * @author Chen * @Description * @create 2019-07-08 13:14 */ @Api(tags = "权限模块") @Controller public class PermissionController { @Autowired private IPermission permissionService; //请求映射处理映射器 //springmvc在启动时候将所有贴有请求映射标签:RequestMapper方法收集起来封装到该对象中 @Autowired private RequestMappingHandlerMapping rmhm; @ResponseBody @GetMapping("reload") public Map<String,Object> reload(){ Map<String,Object> map = new HashMap<String, Object>(); //将系统中所有权限表达式加载进入数据库 //0:从数据库中查询出所有权限表达式,然后对比,如果已经存在了,跳过,不存在添加 List<String> resourcesList = permissionService.getAllResource(); //1:获取controller中所有带有@RequestMapper标签的方法 Map<RequestMappingInfo, HandlerMethod> handlerMethods = rmhm.getHandlerMethods(); Collection<HandlerMethod> methods = handlerMethods.values(); for (HandlerMethod method : methods) { //2:遍历所有方法,判断当前方法是否贴有@RequiresPermissions权限控制标签 RequiresPermissions anno = method.getMethodAnnotation(RequiresPermissions.class); if(anno != null){ //3:如果有,解析得到权限表达式,封装成Permission对象保存到Permission表中 //权限表达式 String resource = anno.value()[0]; //去除重复的 if(resourcesList.contains(resource)){ continue; } Permission p = new Permission(); p.setResource(resource); p.setCreateTime(new Date()); //设置权限名称 p.setName(method.getMethodAnnotation(PermissionName.class).value()); //保存 permissionService.addPermission(p); } } map.put("type","success"); map.put("msg","加载成功!"); return map; } }
异常的处理
/** * @author Chen * @Description 全局异常处理 * @create 2019-07-08 13:14 */ @ControllerAdvice public class GlobalExceptionHandler { /** * @Author * 处理自定义异常 **/ @ExceptionHandler(MyException.class) @ResponseBody public Map<String,Object> handlerMyException(MyException exception){ Map<String,Object> map = new HashMap<>(); map.put("errorCode", exception.getStatus()); map.put("errorMsg", exception.getMessage()); return map; } /** * 权限异常 * @param request * @param response * @return */ @ResponseBody @ExceptionHandler(UnauthorizedException.class) public Responsive authorizationException(HttpServletRequest request, HttpServletResponse response) { return Responsive.of(400,"无权限"); } /** * @Description 处理未知异常 **/ @ExceptionHandler(Exception.class) @ResponseBody public Map<String,Object> handlerException(Exception exception){ Map<String,Object> map = new HashMap<>(); map.put("errorCode", 500); map.put("errorMsg", "未知错误"); return map; } }