1 依赖导入
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
数据库表数据初始化涉及三张表:用户表、角色表和权限表
自定义 realm,自定义 realm 需要继承 AuthorizingRealm 类,因为该类封装了很多方法,它也是一步步继承自 Realm 类的,继承了 AuthorizingRealm 类后,需要重写两个方法:
doGetAuthenticationInfo() 方法:用来验证当前登录的用户,获取认证信息
doGetAuthorizationInfo() 方法:用来为当前登陆成功的用户授予权限和角色
/**
* 自定义realm
*/
public class MyRealm extends AuthorizingRealm {
@Resource
private UserService userService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
// 获取用户名
String username = (String) principalCollection.getPrimaryPrincipal();
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
// 给该用户设置角色,角色信息存在role表中取
authorizationInfo.setRoles(userService.getRoles(username));
// 给该用户设置权限,权限信息存在permission表中取
authorizationInfo.setStringPermissions(userService.getPermissions(username));
return authorizationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
// 根据token获取用户名,如果您不知道该该token怎么来的,先可以不管,下文会解释
String username = (String) authenticationToken.getPrincipal();
// 根据用户名从数据库中查询该用户
User user = userService.getByUsername(username);
if(user != null) {
// 把当前用户存到session中
SecurityUtils.getSubject().getSession().setAttribute("user", user);
// 传入用户名和密码进行身份认证,并返回认证信息
AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), "myRealm");
return authcInfo;
} else {
return null;
}
}
}
Shiro 配置
@Configuration
public class ShiroConfig {
private static final Logger logger = LoggerFactory.getLogger(ShiroConfig.class);
/**
* 注入自定义的realm
* @return MyRealm
*/
@Bean
public MyRealm myAuthRealm() {
MyRealm myRealm = new MyRealm();
logger.info("====myRealm注册完成=====");
return myRealm;
}
}
配置安全管理器 SecurityManager:
@Configuration
public class ShiroConfig {
private static final Logger logger = LoggerFactory.getLogger(ShiroConfig.class);
/**
* 注入安全管理器
* @return SecurityManager
*/
@Bean
public SecurityManager securityManager() {
// 将自定义realm加进来
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(myAuthRealm());
logger.info("====securityManager注册完成====");
return securityManager;
}
}
配置 Shiro 过滤器:
@Configuration
public class ShiroConfig {
private static final Logger logger = LoggerFactory.getLogger(ShiroConfig.class);
/**
* 注入Shiro过滤器
* @param securityManager 安全管理器
* @return ShiroFilterFactoryBean
*/
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
// 定义shiroFactoryBean
ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
// 设置自定义的securityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 设置默认登录的url,身份认证失败会访问该url
shiroFilterFactoryBean.setLoginUrl("/login");
// 设置成功之后要跳转的链接
shiroFilterFactoryBean.setSuccessUrl("/success");
// 设置未授权界面,权限认证失败会访问该url
shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");
// LinkedHashMap是有序的,进行顺序拦截器配置
Map<String,String> filterChainMap = new LinkedHashMap<>();
// 配置可以匿名访问的地址,可以根据实际情况自己添加,放行一些静态资源等,anon表示放行
filterChainMap.put("/css/**", "anon");
filterChainMap.put("/imgs/**", "anon");
filterChainMap.put("/js/**", "anon");
filterChainMap.put("/swagger-*/**", "anon");
filterChainMap.put("/swagger-ui.html/**", "anon");
// 登录url 放行
filterChainMap.put("/login", "anon");
// “/user/admin” 开头的需要身份认证,authc表示要身份认证
filterChainMap.put("/user/admin*", "authc");
// “/user/student” 开头的需要角色认证,是“admin”才允许
filterChainMap.put("/user/student*/**", "roles[admin]");
// “/user/teacher” 开头的需要权限认证,是“user:create”才允许
filterChainMap.put("/user/teacher*/**", "perms[\"user:create\"]");
// 配置logout过滤器
filterChainMap.put("/logout", "logout");
// 设置shiroFilterFactoryBean的FilterChainDefinitionMap
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainMap);
logger.info("====shiroFilterFactoryBean注册完成====");
return shiroFilterFactoryBean;
}
}
Shiro 进行认证:
身份、角色、权限认证接口
@Controller
@RequestMapping("/user")
public class UserController {
/**
* 身份认证测试接口
* @param request
* @return
*/
@RequestMapping("/admin")
public String admin(HttpServletRequest request) {
Object user = request.getSession().getAttribute("user");
return "success";
}
/**
* 角色认证测试接口
* @param request
* @return
*/
@RequestMapping("/student")
public String student(HttpServletRequest request) {
return "success";
}
/**
* 权限认证测试接口
* @param request
* @return
*/
@RequestMapping("/teacher")
public String teacher(HttpServletRequest request) {
return "success";
}
}
用户登录接口
@Controller
@RequestMapping("/user")
public class UserController {
/**
* 用户登录接口
* @param user user
* @param request request
* @return string
*/
@PostMapping("/login")
public String login(User user, HttpServletRequest request) {
// 根据用户名和密码创建token
UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword());
// 获取subject认证主体
Subject subject = SecurityUtils.getSubject();
try{
// 开始认证,这一步会跳到我们自定义的realm中
subject.login(token);
request.getSession().setAttribute("user", user);
return "success";
}catch(Exception e){
e.printStackTrace();
request.getSession().setAttribute("user", user);
request.setAttribute("error", "用户名或密码错误!");
return "login";
}
}
}