一、shiro数据库
大概需要五个数据库
第一个 user_table 用户表
第二个role_table 角色表
第三个 auth_table 权限表
第四个user_role_table 用户表跟权限表关联,第五个role_auth_table 权限跟角色表关联,在这里大家可以根据自己需求的不同设计不同的数据库。
二、集成Spring Boot
1、集成pom文件
<!-- shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.crazycake</groupId>
<artifactId>shiro-redis</artifactId>
<version>3.1.0</version>
</dependency>
2、配置shiro文件
需要建三个实体类,跟数据库对应
AuthDO 权限表
/** 主键Id */
private Integer id;
/** 权限编号 */
private String authCode;
/** 权限名称 */
private String authName;
/** 权限请求的url */
private String authUrl;
/** 权限的名称 */
private String authPermission;
/** 权限是否有效 1.有效 0.无效 */
private Integer authAva;
/** 权限类型 1菜单 2按钮 */
private Integer authType;
/** 权限描述 */
private String authDes;
RoleDO 角色表
/** 主键Id */
private Integer id;
/** 角色是否生效 1.生效 0.失效 */
private Integer roleAva;
/** 角色描述 */
private String roleDes;
/** 角色名称 */
private String roleName;
UserDO 用户表
/** 用户Id */
private Integer Id;
/** 用户姓名 */
private String username;
/** 用户密码 */
private String password;
/** 状态 1:正常 2:禁用 */
private Integer userStatic;
配置ShiroRealm,这里需要配置UserService
查询用户角色
select Id,role_ava,role_des,role_name from role_table where Id in(select role_id from user_role_table where user_id = #{userId}) and >role_ava = 1
查询用户权限
select Id,auth_code,auth_name,auth_url,auth_permission,auth_ava,auth_type,auth_des from auth_table where Id in(select auth_id from role_auth_table where role_id in (select role_id from user_role_table where user_id = #{userId})) and auth_ava =1
package com.xiaofeixia.shiro;
import java.util.List;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
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.springframework.beans.factory.annotation.Autowired;
import com.xiaofeixia.model.AuthDO;
import com.xiaofeixia.model.RoleDO;
import com.xiaofeixia.model.UserDO;
import com.xiaofeixia.service.UserService;
/**
*
* @author lcc
* @data :2019年5月23日 下午2:48:06
*/
public class ShiroRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
/**
* 权限赋值
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
UserDO user = (UserDO) principals.getPrimaryPrincipal();
try {
// 查询用户拥有的角色
List<RoleDO> list = userService.listRoleByUserId(user.getId());
for (RoleDO role : list) {
// 把查询到角色放到shiro里面
authorizationInfo.addRole(role.getRoleDes());
}
// 查询用户角色拥有的权限
List<AuthDO> authDOs = userService.listAuthByUserId(user.getId());
for (AuthDO authDO : authDOs) {
// 把权限放到
authorizationInfo.addStringPermission(authDO.getAuthUrl());
}
} catch (Exception e) {
e.printStackTrace();
}
return authorizationInfo;
}
/**
* 用户验证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
/** 获取用户的输入账号 */
String username = (String)token.getPrincipal();
/** 用户输入的密码 */
//String password = (String) token.getCredentials();
String password = new String((char[]) token.getCredentials());
/** 可以做缓存,shiro有缓存机制 2分钟请求一次 */
UserDO user = userService.getUserLogin(username);
if (user == null) {
/** 账号为空 */
throw new UnknownAccountException();
}
if (password.equals(user.getPassword())) {
/** 被禁用 */
if (user.getUserStatic() == 2) {
throw new LockedAccountException();
}
SimpleAuthenticationInfo authorizationInfo = new SimpleAuthenticationInfo(user,user.getPassword().toCharArray(),getName());
return authorizationInfo;
}else {
/** 密码不对 */
throw new IncorrectCredentialsException();
}
}
}
配置 ShiroJurisdiction
package com.xiaofeixia.shiro;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.yuyi.full.handler.exception.ResultBO;
import org.yuyi.full.handler.exception.ResultTool;
import com.xiaofeixia.exception.ExceptionEnum;
/**
* 权限提示
* @author lcc
* @data :2019年5月24日 下午2:41:55
*/
@RestControllerAdvice
public class ShiroJurisdiction {
@ExceptionHandler(value={AuthorizationException.class,UnauthorizedException.class})
public ResultBO<Object> unAuthorizationExceptionHandler(Exception e){
if (e instanceof UnauthorizedException) {
// 权限异常
return ResultTool.error(ExceptionEnum.NO_AUTH);
}else{
// 系统异常
return ResultTool.error(ExceptionEnum.EXCEPTION);
}
}
}
配置ShiroException 配置未登录异常
package com.xiaofeixia.shiro;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
/**
* 全局异常
* @author lcc
* @data :2019年5月24日 下午2:58:13
*/
public class ShiroException extends FormAuthenticationFilter {
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
return super.isAccessAllowed(request, response, mappedValue);
}
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
Subject subject = SecurityUtils.getSubject();
Object user = subject.getPrincipal();
/**获取不到用户,即用户未登录*/
if (Objects.equals(user, null)) {
Map<String, Object> result = new HashMap<String, Object>();
result.put("code", 100);
result.put("msg", "未登录");
result.put("data",null);
httpServletResponse.setCharacterEncoding("UTF-8");
httpServletResponse.setContentType("application/json");
httpServletResponse.getWriter().write(JSONObject.toJSONString(result,SerializerFeature.WriteMapNullValue));
}
return false;
}
}
配置 ShiroConfig 过滤链
package com.xiaofeixia.shiro;
import java.util.LinkedHashMap;
import java.util.Map;
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.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.apache.shiro.mgt.SecurityManager;
/**
* 配置shiro 过滤链
* @author lcc
* @data :2019年5月23日 下午5:06:18
*/
@Configuration
public class ShiroConfig {
/**
* 自定义过滤
*/
@Bean
public ShiroFilterFactoryBean shirFiter(SecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
/** 配置自己的过滤链 */
Map<String,String> filterChainDefinitionMap = new LinkedHashMap<>();
filterChainDefinitionMap.put("/login", "anon");
filterChainDefinitionMap.put("/cache", "anon");
filterChainDefinitionMap.put("/favicon.ico", "anon");
/** 拦截其他所以接口 */
//filterChainDefinitionMap.put("/**", "authc");
shiroFilterFactoryBean.setUnauthorizedUrl("/user/unauth");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
/**
* 没有登录
* @return
*/
@Bean
public ShiroException shiroException(){
ShiroException shiroException = new ShiroException();
return shiroException;
}
/**
* shiro 用户数据注入
*/
@Bean
public ShiroRealm shiroRealm(){
ShiroRealm shiroRealm = new ShiroRealm();
return shiroRealm;
}
/**
* 配置管理层。即安全控制层
*/
@Bean
public SecurityManager securityManager(){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(shiroRealm());
return securityManager;
}
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
return advisorAutoProxyCreator;
}
/**
* 开启shiro aop注解支持 使用代理方式所以需要开启代码支持
* 一定要写入上面advisorAutoProxyCreator()自动代理。不然AOP注解不会生效
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
}
登录
package com.xiaofeixia.controller;
import java.io.Serializable;
import java.util.List;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.yuyi.full.handler.exception.ResultBO;
import org.yuyi.full.handler.exception.ResultTool;
import com.alibaba.fastjson.JSONObject;
import com.xiaofeixia.exception.ExceptionEnum;
import com.xiaofeixia.model.RoleDO;
import com.xiaofeixia.model.UserDO;
import com.xiaofeixia.service.UserService;
/**
* 登录
* @author lcc
* @data :2019年5月23日 下午5:34:03
*/
@RestController
public class LoginController {
@Autowired
private UserService userService;
/**
* 登录
* @param username 账号
* @param password 密码
* @return
* @throws Exception
*/
@GetMapping("/login")
public ResultBO<?> login(
@RequestParam String username,
@RequestParam String password
) throws Exception{
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
Subject subject = SecurityUtils.getSubject();
try {
Serializable SessionId = subject.getSession().getId();
subject.login(token);
JSONObject json = new JSONObject();
json.put("token",SessionId);
return ResultTool.success(json);
} catch (UnknownAccountException e) {
// 用户名不存在
return ResultTool.error(ExceptionEnum.NAMEFALURE);
} catch (IncorrectCredentialsException e) {
// 密码错误
return ResultTool.error(ExceptionEnum.WORDFALURE);
} catch (LockedAccountException e) {
// 账号异常不能登录
return ResultTool.error(ExceptionEnum.MODIFY_THE_FAILURE);
}
}
@GetMapping("test")
//拥有此权限的才可以访问
@RequiresPermissions("test")
//拥有此角色的才可以访问
@RequiresRoles("admin")
public ResultBO<?> test() throws Exception{
List<UserDO> list = userService.listUser();
return ResultTool.success(list);
}
}