这是一个采用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 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 filterChainDefinitionMap = new LinkedHashMap();
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"; //不成功跳转到 未认证页面
}
}
}
剩下的就是一些路由跳转了,这里就不讲了。
有问题的可以评论交流~