Shiro的基本概念
三个核心组件:Subject, SecurityManager 和 Realms.
Subject:即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。
Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。
SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。
Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。
从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。
Shiro内置了可以连接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、类似INI的文本配置资源以及属性文件等。如果系统默认的Realm不能满足需求,你还可以插入代表自定义数据源的自己的Realm实现。
Shiro的三大核心API
1、subject:用户主体
2、SecurityManager:安全管理器(管理所有的subject,关联Realm)
3、Realm:连接数据的桥梁(连接数据库)
Maven导包
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.5.2</version>
</dependency>
认证和授权
package com.Configation;
import com.Mapper.UserAccount;
import com.Service.UserAccountService;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
public class MyRealm extends AuthorizingRealm {
@Autowired
UserAccountService service;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取登录用户名
String name = (String) principalCollection.getPrimaryPrincipal();
//查询用户名称
User user = loginService.getUserByName(name);
//添加角色和权限
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
for (Role role : user.getRoles()) {
//添加角色
simpleAuthorizationInfo.addRole(role.getRoleName());
//添加权限
for (Permissions permissions : role.getPermissions()) {
simpleAuthorizationInfo.addStringPermission(permissions.getPermissionsName());
}
}
return simpleAuthorizationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("-------执行了--------");
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
UserAccount userAccount = service.GetUser(token.getUsername());
if(userAccount != null){
//若密码不正确则返回IncorrectCredentialsException异常
return new SimpleAuthenticationInfo(userAccount,userAccount.getPassword(), getName());
}
//若用户名不存在则返回UnknownAccountException异常
return null;
}
}
ShiroConfig配置
package com.Configation;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
@Configuration
public class ShiroConfig {
/**
* 创建ShiroFilterFactoryBean
*/
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
//添加Shiro内置过滤器
/**
* Shiro内置过滤器,可以实现权限相关的拦截器
* 常用的有:
* anon:无需认证就能访问
authc:必须认证才能访问 filterMap.put("/test", "anon");
// filterMap.put("/login", "anon");
// filterMap.put("/*", "authc");
user:必须拥有 “记住我” 功能才能使用
perms:拥有对某个资源的权限才能访问
role: 拥有对某个角色权限才能访问
*/
LinkedHashMap<String, String> filterMap = new LinkedHashMap<String,String>();
// filterMap.put("/add", "authc");
// filterMap.put("/update", "authc");
//放行的用户放在前面
//
//修改登录页面
shiroFilterFactoryBean.setLoginUrl("/toLogin");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
/**
* 创建DefaultWebSecurityManager
*/
@Bean(name="securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("MyRealm") MyRealm myRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//关联Realm
securityManager.setRealm(myRealm);
return securityManager;
}
/**
* 创建Realm对象(第一步)
* @Bean 将方法返回的对象放入Sprin环境进行管理
*/
@Bean(name="MyRealm")
public MyRealm myRealm() {
return new MyRealm();
}
}
LoginController
因为我这个是前后的分离的项目,所有和别的博主写法不一样!
@PostMapping("/Login")
public Result Login(@RequestBody Map<String,String> map){
/**
* 使用shiro编写认证操作
*/
//获取subject
Subject subject = SecurityUtils.getSubject();
//封装用户数据
UsernamePasswordToken token = new UsernamePasswordToken(map.get("Username"), map.get("Password"));
//执行登录方法
try {
subject.login(token);
//如果没有异常,登录成功
return new Result(200,"登录成功!");
}catch (UnknownAccountException e){
//如果有异常,登录失败,如果发生UnknownAccountException,说明用户名不存在
return new Result(400,"用户名不存在");
}catch (IncorrectCredentialsException e){
//如果发生IncorrectCredentialsException,说明密码错误
return new Result(400,"密码错误");
}}