上一章:https://blog.csdn.net/qq_41780372/article/details/104823854
一、修改生成的实体,创建查询用户信息的方法
1.一个用户是对应多个角色,一个角色对应多个权限(菜单)。
我们在用户实体上面新增一个角色集合 SysUser.java
List<SysRole> roles;
在角色上面增加权限集合 SysRole.java
List<SysMenu> sysMenus;
记得两个属性上面均需要加上注解@TableField(exist = false),否则在查询数据库时mybaits-plus会把这个当做一个数据库字段进行查询。
2.新增加一个登陆的service,创建一个根据用户名查用户及所有角色和权限的方法。
SysLoginService.java内增加一个接口
SysUser getUserByName(String username);
SysLoginServiceImpl.java内实现接口
@Service
public class SysLoginServiceImpl implements SysLoginService {
@Autowired
private SysUserServiceImpl sysUserService;
@Autowired
private SysRoleServiceImpl sysRoleService;
@Autowired
private SysRoleMenuServiceImpl sysRoleMenuService;
@Autowired
private SysMenuServiceImpl sysMenuService;
@Autowired
private SysUserRoleServiceImpl sysUserRoleService;
@Override
public SysUser getUserByName(String username) {
SysUser sysUser=sysUserService.getOne(new QueryWrapper<SysUser>().eq("username",username));
if(sysUser!=null){
List<SysUserRole> sysUserRoles=sysUserRoleService.list(new QueryWrapper<SysUserRole>().eq("user_id",sysUser.getUserId()));
List<SysRole> sysRoles=new ArrayList<>();
for(SysUserRole sysUserRole:sysUserRoles){
SysRole sysRole=sysRoleService.getById(sysUserRole.getRoleId());
List<SysMenu> sysMenuList=new ArrayList<>();
List<SysRoleMenu> roleMenuList=sysRoleMenuService.list(new QueryWrapper<SysRoleMenu>().eq("role_id",sysUserRole.getRoleId()));
for(SysRoleMenu sysRoleMenu:roleMenuList){
sysMenuList.add(sysMenuService.getById(sysRoleMenu.getMenuId()));
}
sysRole.setSysMenus(sysMenuList);
sysRoles.add(sysRole);
}
sysUser.setRoles(sysRoles);
}
return sysUser;
}
}
二、编辑shiro的配置。
编辑CustomRealm.java
package cn.mvapi.xiaobao.common.shiro;
import cn.mvapi.xiaobao.common.system.entity.SysMenu;
import cn.mvapi.xiaobao.common.system.entity.SysRole;
import cn.mvapi.xiaobao.common.system.entity.SysUser;
import cn.mvapi.xiaobao.common.system.service.SysUserService;
import cn.mvapi.xiaobao.common.system.service.impl.SysLoginServiceImpl;
import cn.mvapi.xiaobao.common.system.service.impl.SysUserServiceImpl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
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.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
public class CustomRealm extends AuthorizingRealm {
@Autowired
private SysLoginServiceImpl sysLoginService;
@Autowired
private SysUserServiceImpl sysUserService;
//进入角色授权 该方法是将用户的角色及权限全部查出来
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取登录用户名
String username = (String) principalCollection.getPrimaryPrincipal();
//根据用户名去数据库查询用户信息
SysUser sysUser = sysLoginService.getUserByName(username);//new QueryWrapper<SysUser>().eq("username",username));
//添加角色和权限
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
for (SysRole role : sysUser.getRoles()) {
//添加角色
simpleAuthorizationInfo.addRole(role.getRoleName());
//添加权限
for (SysMenu sysMenu : role.getSysMenus()) {
if(sysMenu.getPerms()!=null&&!sysMenu.getPerms().trim().equals("")){
for(String str:sysMenu.getPerms().split(",")){
simpleAuthorizationInfo.addStringPermission(str);
}
}
}
}
return simpleAuthorizationInfo;
}
//主要用于账号密码校验,通过用户名查出数据库内的密码,交给shiro校验
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//加这一步的目的是在Post请求的时候会先进认证,然后在到请求
if (authenticationToken.getPrincipal() == null) {
return null;
}
//获取用户信息
String name = authenticationToken.getPrincipal().toString();
SysUser user = sysUserService.getOne(new QueryWrapper<SysUser>().eq("username",name));
if (user == null) {
//这里返回后会报出对应异常
return null;
} else {
//这里验证authenticationToken和simpleAuthenticationInfo的信息
//用户名–此处传的是用户对象
//密码—从数据库中获取的密码
//getName() //当前的realm名
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(name, user.getPassword().toString(), getName());
return simpleAuthenticationInfo;
}
}
}
shiro配置 ShiroConfig.java
将上面的自定义realm添加到容器内,另外如果有多种校验方式可以添加多个realm。
配置拦截的路径和跳转条件。
package cn.mvapi.xiaobao.common.shiro;
import org.apache.shiro.mgt.SecurityManager;
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.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
//不加这个注解不生效,具体不详
@Bean
@ConditionalOnMissingBean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
defaultAAP.setProxyTargetClass(true);
return defaultAAP;
}
//将自己的验证方式加入容器
@Bean
public CustomRealm myShiroRealm() {
CustomRealm customRealm = new CustomRealm();
return customRealm;
}
//权限管理,配置主要是Realm的管理认证
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myShiroRealm());
return securityManager;
}
//Filter工厂,设置对应的过滤条件和跳转条件
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String, String> map = new HashMap<>();
map.put("/test/**","anon");
map.put("/public/**","anon");
map.put("/plugin/**","anon");
//登出
map.put("/logout", "logout");
//对所有用户认证
map.put("/admin/**", "authc");
map.put("/user/**", "authc");
//登录
shiroFilterFactoryBean.setLoginUrl("/login/index.html");
//首页
shiroFilterFactoryBean.setSuccessUrl("/index");
//错误页面,认证不通过跳转
shiroFilterFactoryBean.setUnauthorizedUrl("/login/index.html");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}
//加入注解的使用,不加入这个注解不生效
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
}
三、编辑登录功能,测试功能是否正常。
1.编辑通用的数据返回实体。ReturnData.java
会使用枚举的话这里也可以用上。
public class ReturnData {
private int code;
private String msg;
private Object date;
public ReturnData() {
}
public ReturnData(int code, String msg, Object date) {
this.code = code;
this.msg = msg;
this.date = date;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Object getDate() {
return date;
}
public void setDate(Object date) {
this.date = date;
}
}
编辑登录控制器及相应的权限测试方法。SysLoginController.java
package cn.mvapi.xiaobao.common.system.controller;
import cn.mvapi.xiaobao.common.system.entity.ReturnData;
import cn.mvapi.xiaobao.common.system.entity.SysUser;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
//import com.sun.jndi.toolkit.url.UrlUtil;
//import org.apache.commons.codec.net.URLCodec;
@Controller
public class SysLoginController {
@ResponseBody
@RequestMapping("/login")
public ReturnData login(SysUser user) {
//添加用户认证信息
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(
user.getUsername(),
user.getPassword()
);
String error="";
try {
//进行验证,这里可以捕获异常,然后返回对应信息
subject.login(usernamePasswordToken);
// subject.checkRole("admin");
// subject.checkPermissions("query", "add");
} catch (AuthenticationException e) {
//e.printStackTrace();
// return "账号或密码错误!";
return new ReturnData(201,"账号或密码错误!",null);
} catch (AuthorizationException e) {
// e.printStackTrace();
return new ReturnData(202,"您没有权限!",null);
// return "没有权限";
}
return new ReturnData(200,"登录成功!",null);
}
//注解验角色和权限
@RequiresPermissions("sys:role:delete")
@RequestMapping("/delete")
@ResponseBody
public String index() {
return "delete";
}
@RequiresPermissions("sys:user:save")
@RequestMapping("/save")
@ResponseBody
public String save() {
return "save";
}
//@RequiresPermissions("sys:user:save")
@RequiresRoles("管理员")
@RequestMapping("/role")
@ResponseBody
public String role() {
return "role";
}
@RequiresPermissions("sys:role:otherpermission")
@RequestMapping("/otherPermission")
@ResponseBody
public String others() {
return "用户不存在的权限";
}
@RequiresRoles("otherRoles")
@RequestMapping("/otherRoles")
@ResponseBody
public String otherRoles() {
return "用户不存在的角色";
}
}
启动项目测试功能是否正常。
未登录情况下访问这里会抛出错误http://localhost:8081/save
访问登录接口:http://localhost:8081/login/?username=admin&password=123
提示登录成功后再次访问上面接口 ,界面显示save代表正常。
访问http://localhost:8081/otherPermission
和http://localhost:8081/otherRoles 系统会抛出错误,因为当前用户没有这个角色和权限。
本次教程结束!
上一章:https://blog.csdn.net/qq_41780372/article/details/104823854
下一章:https://blog.csdn.net/qq_41780372/article/details/105096733
github地址:https://github.com/xiaobaos/springboot
码云地址:https://gitee.com/xiaobaomeat/springboot
项目优先更新到github上面。
下一章:引入界面。