springBoot整合shiro实现权限控制

1.pom.xml


        org.springframework.boot
        spring-boot-starter-parent
        1.5.9.RELEASE
    

        
            org.apache.shiro
            shiro-spring
            1.3.2
        
        
        
            com.github.theborakompanioni
            thymeleaf-extras-shiro
            1.2.1
        

2.config

package com.xlt.xfzb.web.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.xlt.xfzb.web.security.UserRealm;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

/**
 * @Classname ShiroConfiguration
 * @Description 权限控制设置
 * @Date 2020/3/27 17:47
 * @Created by xm
 */
@Configuration
public class ShiroConfiguration {

    // 创建自定义 realm
    @Bean
    public UserRealm userRealm() {
        UserRealm userRealm = new UserRealm();
        return userRealm;
    }

    // 创建 SecurityManager 对象
    @Bean
    public DefaultWebSecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(userRealm());
        return securityManager;
    }

    // Filter工厂,设置对应的过滤条件和跳转条件
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        /**
         * anon:匿名用户可访问
         * authc:认证用户可访问
         * user:使用rememberMe可访问
         * perms:对应权限可访问
         * role:对应角色权限可访问
         */
        Map map = new HashMap<>();
        // 开放登录接口
        map.put("/login", "anon");
        map.put("/error", "anon");
        map.put("/img/**","anon");
        map.put("/css/**","anon");
        map.put("/lib/**","anon");
        map.put("/js/**","anon");
        // 对所有用户认证
        map.put("/**", "authc");
        // 登出
        map.put("/logout", "logout");
        // 登录
        // 注意:这里配置的 /login 是指到 @RequestMapping(value="/login")中的 /login
        shiroFilterFactoryBean.setLoginUrl("/login");
        // 首页
        shiroFilterFactoryBean.setSuccessUrl("/index");
        // 错误页面,认证不通过跳转
        shiroFilterFactoryBean.setUnauthorizedUrl("/error/unAuth");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        return shiroFilterFactoryBean;
    }

    // 加入注解的使用,不加这个,注解不生效
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    // 跟上面的注解配置搭配使用,有时候加了上面的配置后注解不生效,需要加入下面的配置
    @Bean
    @ConditionalOnMissingBean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator app = new DefaultAdvisorAutoProxyCreator();
        app.setProxyTargetClass(true);
        return app;
    }

    //页面标签对象
    @Bean
    public ShiroDialect shiroDialect() {
        return new ShiroDialect();
    }
}

3.依赖实体

用户

package com.xlt.xfzb.web.entity;

import java.util.HashSet;
import java.util.Set;

/**
 * @Classname User
 * @Description 权限测试用户
 * @Date 2020/3/27 17:44
 * @Created by xm
 */
public class UserEntity {

    private String id;

    private String name;

    private String password;
    //账号
    private String account;
    //性别
    private String sex;
    //部门id
    private String deptId;
    //工号
    private String work;
    //自定义集合
    private Set roles = new HashSet();

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Set getRoles() {
        return roles;
    }

    public void setRoles(Set roles) {
        this.roles = roles;
    }

    public String getAccount() {
        return account;
    }

    public void setAccount(String account) {
        this.account = account;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getDeptId() {
        return deptId;
    }

    public void setDeptId(String deptId) {
        this.deptId = deptId;
    }

    public String getWork() {
        return work;
    }

    public void setWork(String work) {
        this.work = work;
    }
}

角色

package com.xlt.xfzb.web.entity;

import java.util.HashSet;
import java.util.Set;

/**
 * @Classname Role
 * @Description TODO
 * @Date 2020/3/30 11:42
 * @Created by xm
 */
public class RoleEntity {

    private String id;
    //姓名
    private String name;
    //备注
    private String remark;
    //自定义菜单实体
    private Set permissions = new HashSet<>();//一个角色有多个权限

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Set getPermissions() {
        return permissions;
    }

    public void setPermissions(Set permissions) {
        this.permissions = permissions;
    }

    public String getRemark() {
        return remark;
    }

    public void setRemark(String remark) {
        this.remark = remark;
    }
}

权限

package com.xlt.xfzb.web.entity;

/**
 * @Classname Permission
 * @Description 权限实体
 * @Date 2020/3/30 11:41
 * @Created by xm
 */
public class PermissionEntity {

    private String id;

    private String name;
    //路径
    private String url;
    //描述
    private String descrirtion;
    //父id
    private String pid;


    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getDescrirtion() {
        return descrirtion;
    }

    public void setDescrirtion(String descrirtion) {
        this.descrirtion = descrirtion;
    }

    public String getPid() {
        return pid;
    }

    public void setPid(String pid) {
        this.pid = pid;
    }
}

4.自定义异常

package com.xlt.xfzb.web.security;

import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
 * @Classname NoPermissionException
 * @Description TODO
 * @Date 2020/3/31 11:16
 * @Created by xm
 */
@ControllerAdvice
public class NoPermissionException {

    // 授权失败,就是说没有该权限
    @ExceptionHandler(UnauthorizedException.class)
    public String handleShiroException(Exception ex) {
        return "/error/unAuth";
    }

    @ResponseBody
    @ExceptionHandler(AuthorizationException.class)
    public String AuthorizationException(Exception ex) {
        return "权限认证失败";
    }
}

5.权限认证

package com.xlt.xfzb.web.security;

import com.netflix.discovery.provider.Serializer;
import com.xlt.xfzb.web.entity.PermissionEntity;
import com.xlt.xfzb.web.entity.RoleEntity;
import com.xlt.xfzb.web.entity.UserEntity;
import com.xlt.xfzb.web.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
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 org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

/**
 * @Classname UserRealm
 * @Description TODO
 * @Date 2020/3/31 11:02
 * @Created by xm
 */
@Service
public class UserRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;

    /**
     * 用户授权
     **/
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(
            PrincipalCollection principalCollection) {

        System.out.println("===执行授权===");

        Subject subject = SecurityUtils.getSubject();
        UserEntity user = (UserEntity)subject.getPrincipal();
        if(user != null){
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            // 角色字符串集合
            Collection rolesCollection = new HashSet<>();
            // 权限字符串集合
            Collection premissionCollection = new HashSet<>();
            // 读取并赋值用户角色与权限
            Set roles = user.getRoles();
            for(RoleEntity role : roles){
                rolesCollection.add(role.getName());
                Set permissions = role.getPermissions();
                for (PermissionEntity permission : permissions){
                    // 权限名称为PermissionEntity为字段url
                    premissionCollection.add(permission.getUrl());
                }
                info.addStringPermissions(premissionCollection);
            }
            info.addRoles(rolesCollection);
            return info;
        }
        return null;
    }

    /**
     * 用户认证
     **/
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken authenticationToken) throws AuthenticationException {

        System.out.println("===执行认证===");

        UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
        UserEntity bean = userService.findByName(token.getUsername());

        if(bean == null){
            // 用户不存在
            throw new UnknownAccountException();
        } else {
            bean = userService.findById(bean.getId());
            if(null == bean) {
                // 认证失败
                throw new AuthenticationException();
            }
        }

        ByteSource credentialsSalt = ByteSource.Util.bytes(bean.getName());

        return new SimpleAuthenticationInfo(bean, bean.getPassword(),
                credentialsSalt, getName());

    }
}

6.持久层

package com.xlt.xfzb.web.mapper;

import com.xlt.xfzb.web.entity.UserEntity;
import org.springframework.stereotype.Service;

/**
 * @Classname UserMapper
 * @Description 用户测试
 * @Date 2020/3/31 10:45
 * @Created by xm
 */
@Service
public interface UserMapper {

    // 根据用户名称,查询用户信息
     UserEntity findByName(String name);

    // 根据用户id,查询用户信息、角色、权限
     UserEntity findById(String id);
}




    
        
        
        
        
            
            
            
                
                
                
            
        
    

    

    

7.service

package com.xlt.xfzb.web.service;

import com.xlt.xfzb.web.entity.UserEntity;

/**
 * @Classname UserService
 * @Description 用户相关业务接口
 * @Date 2020/3/30 11:48
 * @Created by xm
 */
public interface UserService {

    /**
     * 根据用户名称查询用户信息
     * @param name
     * @return
     */
    UserEntity findByName(String name);

    /**
     * 根据用户ID查询用户角色及权限
     * @param id
     * @return
     */
    UserEntity findById(String id);
}
package com.xlt.xfzb.web.service.impl;

import com.xlt.xfzb.web.entity.UserEntity;
import com.xlt.xfzb.web.mapper.UserMapper;
import com.xlt.xfzb.web.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @Classname UserService
 * @Description 用户相关业务接口实现
 * @Date 2020/3/30 11:48
 * @Created by xm
 */
@Service
public class UserServiceImpl implements UserService {

    //测试用户持久层
    @Autowired
    private UserMapper userMapper;

    /**
     * 根据用户名称查询用户信息
     * @param name
     * @return
     */
    @Override
    public UserEntity findByName(String name) {
        return userMapper.findByName(name);
    }

    /**
     * 根据用户ID查询用户角色及权限
     * @param id
     * @return
     */
    @Override
    public UserEntity findById(String id) {
        return userMapper.findById(id);
    }
}

8.controller

package com.xlt.xfzb.web.controller;


import com.xlt.xfzb.web.entity.UserEntity;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * @Classname MainController
 * @Description 主页验证前端控制器
 * @Date 2020/3/31 11:18
 * @Created by xm
 */
@Controller
public class MainController {

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

    /**
     * 主页跳转
     * @param model 携带当前登录用户信息返回
     * @return
     */
    @RequestMapping("/index")
    public String index(Model model){
        UserEntity user = (UserEntity) SecurityUtils.getSubject().getPrincipal();
        model.addAttribute("uid",user.getId());
        model.addAttribute("uname",user.getName());
        log.info("当前登录用户-----"+user.getName());
        return "index";
    }

    /**
     * 登录接口+登录页面
     * @param request
     * @param response
     * @return
     */
    @RequestMapping("/login")
    public String login(HttpServletRequest request, HttpServletResponse response){
        response.setHeader("root", request.getContextPath());
        String userName = request.getParameter("username");
        String password = request.getParameter("password");
        // 等于null说明用户没有登录,只是拦截所有请求到这里,那就直接让用户去登录页面,就不认证了。
        // 如果这里不处理,那个会返回用户名不存在,逻辑上不合理,用户还没登录怎么就用户名不存在?
        if(null == userName) {
            return "login";
        }

        // 1.获取Subject
        Subject subject = SecurityUtils.getSubject();
        // 2.封装用户数据
        UsernamePasswordToken token = new UsernamePasswordToken(userName, password);
        // 3.执行登录方法
        try{
            subject.login(token);
            return "redirect:/index";
        } catch (UnknownAccountException e){
            // 这里是捕获自定义Realm的用户名不存在异常
            log.info("用户名不存在!");
        } catch (IncorrectCredentialsException e){
            log.info("密码错误!");
        } catch (AuthenticationException e) {
            log.info("认证失败!");
        }

        return "login";
    }

    /**
     * 用户登出操作
     * @return
     */
    @RequestMapping("/logout")
    public String logout(){
        Subject subject = SecurityUtils.getSubject();
        if (subject != null) {
            subject.logout();
        }
        return "login";
    }

    /**
     * 错误页面
     * @return
     */
    @RequestMapping("/error/unAuth")
    public String unAuth(){
        return "/error/unAuth";
    }

    @RequestMapping("/err")
    public String err(){
        return "/error/unAuth";
    }


}

9.登录页面 login.html




    
    登录


用户登录


用户名
密码

10.首页 index.HTML





    首页


首页


11.数据库结构

springBoot整合shiro实现权限控制_第1张图片

user 

 springBoot整合shiro实现权限控制_第2张图片

role

springBoot整合shiro实现权限控制_第3张图片 

user_role

springBoot整合shiro实现权限控制_第4张图片 

permission

springBoot整合shiro实现权限控制_第5张图片 

 role_permission

springBoot整合shiro实现权限控制_第6张图片

 12.  页面测试

springBoot整合shiro实现权限控制_第7张图片

你可能感兴趣的:(后端)