导入依赖
<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;
}
}