1.添加shiro依赖
pom.xml
<!--Shiro框架-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.5.3</version>
</dependency>
<!--Thymeleaf关于Shiro框架-->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
2.实体类
User类
@TableName("t_user")
public class User {
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private String username;
private String password;
private Integer roleId;
private Integer isEnable;
private Date createTime;
@TableField(exist = false)
private Role role;
// SET/GET省略
}
Role类
@TableName("t_role")
public class Role {
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@TableField(value = "roleKey")
private String roleKey;
@TableField(value = "roleName")
private String roleName;
@TableField(exist = false)
private List<Permission> permissionList;
// SET/GET省略
}
Permission类
@TableName("t_permission")
public class Permission {
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private String permissionKey;
@TableField(value = "permissionName")
private String title;
/**
* 父节点ID
*/
private Integer pId;
/**
* 节点集合
*/
@TableField(exist = false)
private List<Permission> children = new ArrayList<>();
/**
* 是否被选中
*/
@TableField(exist = false)
private Boolean checked = false;
// SET/GET省略
}
3.添加UserRealm
UserRealm
public class UserRealm extends AuthorizingRealm {
@Autowired
IUserService userService;
/**
* 登录后授权
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
// 获取Subject
Subject subject = SecurityUtils.getSubject();
User user = (User)subject.getPrincipal();
// 根据username从数据库中查询角色和权限
User userRolePermission = userService.getUserRolePermissionByUsername(user.getUsername());
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
List<String> roleList = new ArrayList<>();
// 往Shiro框架中添加角色集合
roleList.add(userRolePermission.getRole().getRoleKey());
simpleAuthorizationInfo.addRoles(roleList);
// 往Shiro框架中添加权限集合
List<String> permissionList = new ArrayList<>();
for (Permission permission:userRolePermission.getRole().getPermissionList()) {
permissionList.add(permission.getPermissionKey());
}
simpleAuthorizationInfo.addStringPermissions(permissionList);
return simpleAuthorizationInfo;
}
/**
* 登录时身份验证
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
// 根据用户名查询用户
User user = userService.getUserByUsername(token.getUsername());
if (user == null) {
// 用户不存在时抛出异常
throw new UnknownAccountException();
} else {
user = userService.getUserById(user.getId());
// 根据ID二次验证
if (user == null) {
// 根据用户ID查询用户不存在时,抛出登录认证异常
throw new AuthenticationException();
}
}
ByteSource byteSource = ByteSource.Util.bytes(user.getUsername());
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(user, user.getPassword(), byteSource, getName());
return simpleAuthenticationInfo;
}
}
4.Shiro配置类
ShiroConfig配置类
@Configuration
public class ShiroConfig {
/**
* 创建自定义 realm
*
* @return
*/
@Bean
public UserRealm userRealm() {
return new UserRealm();
}
/**
* 创建 securityManager 安全管理对象
*/
@Bean
public DefaultWebSecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(userRealm());
return securityManager;
}
/**
* Filter工厂, 设置对应的过滤条件和跳转条件
*
* @param securityManager
* @return
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
/**
* anon: 匿名用户可访问
* authc: 认证用户可访问
* user: 使用rememberMe可访问
* perms: 对应权限可访问
* role: 对应角色权限可访问
*/
Map<String, String> map = new HashMap<>();
// 静态资源放行
//map.put("/static/**", "anon");
//map.put("/css/**", "anon");
//map.put("/lib/**", "anon");
//map.put("/js/**", "anon");
//map.put("/images/**", "anon");
// 转向登陆页面
//map.put("/user/toLogin","anon");
// 登陆动作
//map.put("/user/login", "anon");
// 对登录跳转接口进行释放
//map.put("/error", "anon");
// 对所有用户认证
//map.put("/**", "authc");
// 登出
//map.put("/logout", "logout");
// 登录
// 注意:这里配置的 /toLogin 是指到 @RequestMapping(value="/toLogin")中的 /toLogin
//shiroFilterFactoryBean.setLoginUrl("/user/toLogin");
// 首页
//shiroFilterFactoryBean.setSuccessUrl("/index");
// 错误页面,认证不通过跳转
//shiroFilterFactoryBean.setUnauthorizedUrl("/error/unAuth");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}
/**
* 加入注解的使用,不加这个,注解不生效
*
* @param securityManager
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
/**
* 跟上面的注解配置搭配使用,有时候加了上面的配置后注解不生效,需要加入下面的配置
*
* @return
*/
@Bean
@ConditionalOnMissingBean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
return defaultAdvisorAutoProxyCreator;
}
/**
* 在模板中使用shiro标签
* @return
*/
@Bean(name = "shiroDialect")
public ShiroDialect shiroDialect() {
return new ShiroDialect();
}
}
5.登录验证
UserController
@RestController
@RequestMapping("/user")
public class UserController {
/**
* 日志
*/
private static Logger logger = LoggerFactory.getLogger(UserController.class);
/**
* 登录
* @param user
* @return
*/
@RequestMapping("/login")
public Map login(User user) {
logger.info("执行登录方法 用户名:" + user.getUsername() + "\t" + "密码:" + user.getPassword());
Map<String, String> map = new HashMap<>(1);
// 1.获取Subject
Subject subject = SecurityUtils.getSubject();
// 2.封装用户数据
UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword());
// 3.执行shiro的login方法--会自动调用Realm中的认证方法doGetAuthenticationInfo
try {
subject.login(token);
map.put("flag", "1");
} catch (UnknownAccountException e) {
logger.info("没有此账号");
map.put("flag", "-1");
} catch (IncorrectCredentialsException e) {
logger.info("密码错误");
map.put("flag", "-2");
} catch (AuthenticationException e) {
logger.info("认证失败");
map.put("flag", "-3");
}
return map;
}
}
6.统一报错的信息页面
NoPermissionException
/**
* 全局无权限异常处理类
* @author:ChenXin
* @date 2021/2/8 17:20
*/
@ControllerAdvice
public class NoPermissionException {
/**
* 授权失败, 就是说没有该权限
* @param e
* @return
*/
@ResponseBody
@ExceptionHandler(UnauthorizedException.class)
public String handleShiroException(Exception e) {
return "权限不足";
}
/**
* 认证失败
* @param e
* @return
*/
@ResponseBody
@ExceptionHandler(AuthorizationException.class)
public String authorizationException(Exception e) {
return "权限认证失败";
}
}