主体,代表了当前的“用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是主体,如第三方进程、网络爬虫、机器人等,Subject是一个抽象概念,所有的Subject都绑定到SecurityManager,与Subject的所有交互都会委托给SecurityManager,可以把Subject认为是一个门面;SecurityManager才是实际的执行者.
安全管理器,即所有与安全有关的操作都会与SecurityManager进行交互,是Shiro框架的核心,
管理所有的Subject,类似于Spring MVC的前端控制器DispatcherServlet;
Shiro从Realm中获取安全数据(比如用户、角色、权限),SecurityManager要验证用户身份,
需要从Realm中获取相应的用户进行比较确定用户是否合法;验证用户角色/权限也需要从Realm获得相应数据进行比较,类似于DataSource,安全数据源;它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。
总之:
用户、权限是通过Realm让开发人员自己注入到SecurityManager,从而让SecurityManager能得到合法的用户以及权限进行判断;
创建SpringBoot项目
依赖引入
<dependency>
<groupId>org.apache.shirogroupId>
<artifactId>shiro-spring-boot-starterartifactId>
<version>1.5.3version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.apache.shirogroupId>
<artifactId>shiro-spring-boot-starterartifactId>
<version>1.5.3version>
dependency>
public class CustomerRealm extends AuthorizingRealm {
/**
* 授权逻辑
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了=>授权逻辑PrincipalCollection");
return null;
}
/**
* 认证逻辑
* @param authenticationToken
* @return
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) {
System.out.println("执行了=>认证逻辑AuthenticationToken");
return null;
}
}
基础结构
@Configuration
public class ShiroConfig {
/**
* realm对象
* @return
*/
@Bean
public CustomerRealm myShiroRealm() {
return null;
}
/**
* 权限管理,配置主要是Realm的管理认证
* @return
*/
@Bean
public DefaultWebSecurityManager securityManager() {
return null;
}
/**
* Filter工厂,设置对应的过滤条件和跳转条件
* @param securityManager
* @return
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
return null;
}
}
创建Realm 对象
Realm对象
/**
* Realm对象
* @return
*/
@Bean
public CustomerRealm myShiroRealm() {
return new CustomerRealm();
}
创建DefaultWebSecurityManager
权限管理,配置主要是Realm的管理认证
/**
* 权限管理,配置主要是Realm的管理认证
* @return
*/
@Bean
public DefaultWebSecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myShiroRealm());
return securityManager;
}
创建 ShiroFilterFactoryBean
Filter工厂,设置对应的过滤条件和跳转条件
/**
* Filter工厂,设置对应的过滤条件和跳转条件
* @param securityManager
* @return
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
return shiroFilterFactoryBean;
}
创建一个文件夹controller/LoginController.java
@RestController
public class LoginController {
@GetMapping("/login")
public String login(String userName,String passWord) {
if (StringUtils.isEmpty(userName) || StringUtils.isEmpty(passWord)) {
return "用户名密码不能为空";
}
//用户认证信息
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(userName, passWord);
try {
subject.login(usernamePasswordToken);
} catch (UnknownAccountException e) {
return "用户不存在";
} catch (AuthenticationException e) {
return "用户名密码错误";
} catch (AuthorizationException e) {
return "无权限登录";
}
return "登录成功";
}
}
过滤条件
修改ShiroConfig中的过滤工厂,设置所有的请求都需要认证,放行登录请求。
注意:
这里有一些shiro内置的过滤请求,如下所示:
/**
* Filter工厂,设置对应的过滤条件和跳转条件
*
* @param securityManager
* @return
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String, String> map = new HashMap<>();
//对所有用户认证
map.put("/**", "authc");
//登录
shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}
认证逻辑
shiro会自动帮我们去比对用户名和密码。
在这里,定义了userName 和 passWord ,后续连接数据库后,这里应该是需要通过查询数据库。
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) {
System.out.println("执行了=>认证逻辑AuthenticationToken");
String userName = "admin";
String passWord = "123456";
//这里验证authenticationToken和simpleAuthenticationInfo的信息
return new SimpleAuthenticationInfo(userName, passWord, getName());
}
到这里,我们可以启动我们工程,访问登录接口,测试一番了。
访问地址:http://localhost:8080/login -> 用户名密码不能为空
访问地址:http://localhost:8080/login?userName=wang&passWord=111 -> 用户名密码错误
访问地址: http://localhost:8080/login?userName=admin&passWord=123456 -> 登录成功
到这里,暂时结束了。下一章,会连接数据库,完成登录及权限认证相关操作。