记录springboot整合shiro和thymeleaf实现权限控制

1:导入依赖jar包

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-starter</artifactId>
            <version>1.6.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-web-starter</artifactId>
            <version>1.6.0</version>
        </dependency>
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>

2:编写UserRealm配置类类继承了AuthorizingReaml并重写了其中的两个方法

(1)AuthorizationInfo :

      授权方法:SimpleAuthorizationInfo 通过这个凭证获取到认证之后的账号密码

(2)AuthenticationInfo :

      认证方法:authenticationToken会封装登录的一些信息(用户名、密码)并且由Subject带到此处,
    //User subject = (User) SecurityUtils.getSubject();
    User user = (User) principalCollection.getPrimaryPrincipal();
    上述两个方法都可以获取到认证之后的信息,就是认证SimpleAuthenticationInfo凭证里面存储的值
              通过SimpleAuthorizationInfo来存储该认证之后的用户的角色集合和权限集合。
public class UserRealm extends AuthorizingRealm {

    @Autowired
    UserService userService;
    @Autowired
    RoleService roleService;
    @Autowired
    PermissionService permissionService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("========开始权限验证========");
        //String username = (String) SecurityUtils.getSubject().getPrincipal();

        //User subject = (User) SecurityUtils.getSubject();
        User user = (User) principalCollection.getPrimaryPrincipal();

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //查询登录用户所拥有的角色,并添加角色

        List<Role> roles = roleService.getAllRolesByUid(user.getId());

        for (Role role : roles) {
            info.addRole(role.getName());
            System.out.println(role);
            List<Permission> permissions = permissionService.getAllPermissionByUid(user.getId());
            //查询登录用户所拥有的权限,并添加权限
            for (Permission permission : permissions) {
                System.out.println(permission);
                info.addStringPermission(permission.getName());
            }
        }
        return info;
    }

    //重写验证身份的方法
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("========开始身份验证========");
        String username = (String) authenticationToken.getPrincipal();
        String userpassword = new String((char[]) authenticationToken.getCredentials());

        User user = userService.getOne(new QueryWrapper<User>()
                .eq("id",username)
                .eq("password",userpassword));
        System.out.println(user);
        if (user == null) {
            throw new AccountException("用户名或密码错误");
        }
        return new SimpleAuthenticationInfo(user, userpassword, getName());
    }
}

3:编写shiro的配置类

(容易出错的地方):springboot默认有一个securitymanager的组件,所以我们通过sessionsecuritymanager来代替。

@Configuration
public class ShiroConfig {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Bean(name = "shiroFilterFactoryBean")
    public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager securityManager) {
        logger.info("启动shiroFilter--时间是:" + new Date());
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //这里设置没有登录时,跳转界面
        shiroFilterFactoryBean.setLoginUrl("/");
        //这里是没有授权时,跳转的界面
        shiroFilterFactoryBean.setUnauthorizedUrl("/noAuthc");

        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        filterChainDefinitionMap.put("/", "anon");
        filterChainDefinitionMap.put("/doLogin", "anon");
        filterChainDefinitionMap.put("/jquery-3.4.1/**", "anon");
        filterChainDefinitionMap.put("/layui/**", "anon");
        filterChainDefinitionMap.put("/plugins/**", "anon");

        filterChainDefinitionMap.put("/FinishTask/Performance","perms[performance:list]");

        //filterChainDefinitionMap.put("/student/delete/**","perms[delete]");
        //filterChainDefinitionMap.put("/student/toadd/**", "perms[create]");
        //filterChainDefinitionMap.put("/user/delete/**","perms[delete]");
        //filterChainDefinitionMap.put("/user/toadd/**", "perms[create]");
        //filterChainDefinitionMap.put("/student/toeditstudent/**", "perms[update]");



        //主要这行代码必须放在所有权限设置的最后,不然会导致所有 url 都被拦截 剩余的都需要认证
        filterChainDefinitionMap.put("/**", "authc");


        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;

    }

    /**
     * 配置shiro的生命周期
     * @return
     */
    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean(name = "securityManager")
    public SessionsSecurityManager securityManager() {
        DefaultWebSecurityManager defaultSecurityManager = new DefaultWebSecurityManager();
        defaultSecurityManager.setRealm(userRealm());
        return defaultSecurityManager;
    }

    @Bean("userRealm")
    public UserRealm userRealm() {
        UserRealm userRealm = new UserRealm();
        return userRealm;
    }

    //注解
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor sourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        sourceAdvisor.setSecurityManager(securityManager);
        return sourceAdvisor;
    }

    @Bean
    public ShiroDialect shiroDialect() {
        return new ShiroDialect();
    }

    //配置异常处理,不配置的话没有权限后台报错,前台不会跳转到403页面
    @Bean(name="simpleMappingExceptionResolver")
    public SimpleMappingExceptionResolver
    createSimpleMappingExceptionResolver() {
        SimpleMappingExceptionResolver simpleMappingExceptionResolver = new SimpleMappingExceptionResolver();
        Properties mappings = new Properties();
        mappings.setProperty("DatabaseException", "databaseError");//数据库异常处理
        mappings.setProperty("UnauthorizedException","404");
        simpleMappingExceptionResolver.setExceptionMappings(mappings);  // None by default
        simpleMappingExceptionResolver.setDefaultErrorView("404");    // No default
        simpleMappingExceptionResolver.setExceptionAttribute("ex");     // Default is "exception"
        return simpleMappingExceptionResolver;
    }
}

4:登录的requestMapping

usernamePasswordToken的作用是存储用户的账号和密码,subject.login(usernamePasswordToken);执行登录即可。

@RequestMapping("/doLogin")
    public String doLogin(String username , String password ,
                          Model model, HttpSession session){

        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password);
        try {
            subject.login(usernamePasswordToken);
        } catch (UnknownAccountException uae) {
            model.addAttribute("msg","未知账户");
            return "login";
        } catch (IncorrectCredentialsException ice) {
            model.addAttribute("msg","*密码不正确~");
            return "login";
        } catch (LockedAccountException lae) {
            model.addAttribute("msg","*账户已锁定~");
            return "login";
        } catch (ExcessiveAttemptsException eae) {
            model.addAttribute("msg","*用户名或密码错误次数过多~");
            return "login";
        } catch (AuthenticationException ae) {
            model.addAttribute("msg","*用户名或密码不正确~");
            return "login";
        }
        if (subject.isAuthenticated()) {
            User user = userMapper.selectOne(new QueryWrapper<User>()
                    .eq("id",username)
                    .eq("password",password));
            session.setAttribute("user",user);
            return "index";
        } else {
            usernamePasswordToken.clear();
            model.addAttribute("msg","*未知账户~");
            return "login";
        }
    }

5:和前端html页面进行整合

在需要有权限的地方使用

<shiro:hasPermission name="performance:list">...</shiro:hasPermission>

6:gitee码云地址:

码云

posted @ 2021-03-09 22:59  尹小宝W  阅读(209)  评论(0)    收藏  举报