【提供源码】Springboot Shiro 实现认证授权功能

这是一个采用springboot 与shiro实现授权功能的demo,希望对你有帮助。

github: 项目地址

大家最好可以一边参照源码一边看下面的文章,如果可以的话希望能star一下,谢谢~

项目的整体结构如下:

这是比较通用的web结构,用到了mybatis连接数据库,以及thymeleaf模板


数据库的设计如下:



action表 : (和权限有关的表)


role表 (角色表)


role-action表


user表 



pom.xml的jar包导入之后,要在application.properties之中配置一下。

spring.thymeleaf.prefix=classpath:/templates/       
spring.thymeleaf.suffix=.html   

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/springbootshiro?useUnicode=true&characterEncoding=utf8
spring.datasource.username=****
spring.datasource.password=****

mybatis.mapper-locations=classpath:mybaits/mapper/*.xml

这里面主要配置thymeleaf模板的页面地址,以及mybatis的相关配置。

由于我们是自己设计数据库实现认证和授权的,所以可以自己自定义一个realm来实现这些逻辑:

数据库查询也是在这里使用到的。

package com.example.kiruma.springbootshiro.realm;

import com.example.kiruma.springbootshiro.bean.User;
import com.example.kiruma.springbootshiro.service.UserService;
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.AuthenticatingRealm;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.realm.SimpleAccountRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

@Service("myRealm")
public class MyRealm extends AuthorizingRealm {


    @Autowired
    UserService userService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        String username =(String)principalCollection.getPrimaryPrincipal();
        List<String> permissions=userService.getUserPermissionByUserName(username);
        SimpleAuthorizationInfo simpleAuthorizationInfo=new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.addStringPermissions(permissions);
        return simpleAuthorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        String username=(String)authenticationToken.getPrincipal();
        User user = userService.selectUserByUsername(username);

       
        String password=user.getPassword();
       
        SimpleAuthenticationInfo simpleAuthenticationInfo=
                                    new SimpleAuthenticationInfo(username,password,"myRealm");

        return simpleAuthenticationInfo;
    }



}

数据库查询相关的就不在这里赘述了,可以在源码里面查看。

接下来需要定义一个配置文件,它配置了shiro的realm 以及授权链等:

这里我踩了一个小坑,securityManager.setRealm(myRealm);

这里一开始我是用的是securityManager.setRealm(new MyRealm());

然后运行项目的时候一直报nullpoint exception,后来排查时才发现这个错误,因为我们用到的是spring框架,所以我们myrealm也应该使用依赖注入的方式。

package com.example.kiruma.springbootshiro.configure;


import com.example.kiruma.springbootshiro.realm.MyRealm;

import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;
import java.util.LinkedHashMap;
import java.util.Map;


@Configuration
public class shiroConfig {

    @Resource(name="myRealm")
    MyRealm myRealm;
    /**
     * 拦截器
     * @param securityManager
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){
        System.out.println("shiro 配置 filter");
        ShiroFilterFactoryBean shiroFilterFactoryBean =new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();
        filterChainDefinitionMap.put("/static/**","anon"); //静态资源一律放行
        filterChainDefinitionMap.put("/login","anon");     //login页面无需认证
        filterChainDefinitionMap.put("/login/check","anon");//login check也不用认证

        //与广告相关的路径的规则
        filterChainDefinitionMap.put("/ad","authc");//需要认证
        filterChainDefinitionMap.put("/ad/show","authc,perms[ad:show]");//需要授权
        filterChainDefinitionMap.put("/ad/create","authc,perms[ad:create]");//需要授权




        filterChainDefinitionMap.put("/**","authc");//剩下的也都要授权
        shiroFilterFactoryBean.setLoginUrl("/login");
        shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorizedPage");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return  shiroFilterFactoryBean;

    }


    @Bean
    public SecurityManager securityManager(){
        DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
        securityManager.setRealm(myRealm);
        return securityManager;
    }


}

然后是LoginController:

在check方法里面直接调用shiro去认证。

package com.example.kiruma.springbootshiro.controller;


import com.example.kiruma.springbootshiro.bean.User;
import com.example.kiruma.springbootshiro.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping("/login")
public class LoginController {


    //登陆页面
    @RequestMapping(method = RequestMethod.GET)
    public String login(){
        return "login";
    }


    //登陆检验逻辑
    @RequestMapping(value = "/check",method = RequestMethod.POST)
    public String check(String username,String password){

        UsernamePasswordToken token=new UsernamePasswordToken(username,password);
        org.apache.shiro.subject.Subject subject= SecurityUtils.getSubject();

        try {
            subject.login(token);
            return "index"; //认证成功跳转到成功页面
        }catch (Exception e){
            e.printStackTrace();
            return "unauthenticatedPage";   //不成功跳转到 未认证页面
        }
    }

}

剩下的就是一些路由跳转了,这里就不讲了。

有问题的可以评论交流~


















猜你喜欢

转载自blog.csdn.net/qq_34761108/article/details/80639108