⭐shiro的结构图

⭐shiro内部采用的是session+sessionId进行的会话管理(有状态认证)

⭐当然你也可以整合jwt实现无状态认证

Ok,直接干货!!!!
1. 第一步:加依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>
2.第二步:写一个shiroConfig类
@Configuration
public class ShiroConfig {
/**
* 创建shiro的一个过滤器
*/
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean() {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//设置安全管理器
shiroFilterFactoryBean.setSecurityManager(getDefaultWebSecurityManager());
/**
* 添加shiro的内置过滤器:一般用两种 anon:允许通过;authc:必须认证
* 还有就是user:如果使用rememberMe的功能就可以访问
* perms:该资源必须得到权限资源才可以访问
* role:必须得到角色权限才可以访问
*/
//必须保证顺序插入所以使用LinkedHashMap
Map<String, String> filterMap = new LinkedHashMap<>();
//认证过滤器
filterMap.put("自定义无需认证", "anon");
//filterMap.put("/user/*", "authc");
//授权过滤器
filterMap.put("/user/hello", "perms[自定义]");//例子:user:add
//未认证的跳转页面(也就是未登录的用户)
shiroFilterFactoryBean.setLoginUrl("/toLogin");
//未授权访问跳转的页面(也就是没有权限的用户)
shiroFilterFactoryBean.setUnauthorizedUrl("/error");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
/**
* 创建SecurityManager
*/
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//关联Realm
securityManager.setRealm(getRealm());
return securityManager;
}
/**
* 创建Realm:需要自定义一个realm的类
*/
@Bean
public MyRealm getRealm() {
MyRealm myRealm = new MyRealm();
// 配置 加密 (在加密后,不配置的话会导致登陆密码失败)
myRealm.setCredentialsMatcher(hashedCredentialsMatcher());
return myRealm;
}
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
// 使用md5 算法进行加密
hashedCredentialsMatcher.setHashAlgorithmName("md5");
// 设置散列次数: 意为加密几次
hashedCredentialsMatcher.setHashIterations(2);
return hashedCredentialsMatcher;
}
}
3.第三步:写一个自定义的认证授权Realm
public class MyRealm extends AuthorizingRealm {
/**
* 执行授权逻辑
*
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
// 获取登录用户信息
Object primaryPrincipal = principalCollection.getPrimaryPrincipal();
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//执行授权逻辑
info.addStringPermission("user:add");
return info;
}
/**
* 执行认证逻辑
*
* @param authenticationToken:这个就是前面subject.login()传递过来的token
* @return 认证不通过就返回null
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//执行认证的过程
//从数据库拿出账号密码和用户传递过来的账号密码对比
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) authenticationToken;
String username = usernamePasswordToken.getUsername();
//数据查询账号密码
if (!username.equals("数据库账号")) {
return null;//返回为空,shiro会抛出UnKnowAccountException(也就是账号不存在)
}
//密码不需要判断,直接返回一个AuthenticationInfo的实现类,把数据库密码做参数,shiro会自己判断的
//shiro内置的加密算法
ByteSource credentialsSalt = ByteSource.Util.bytes("user.getUsername" + "user.getSalt()");//从数据库查询的
return new SimpleAuthenticationInfo(username, "数据库加密之后的密码", credentialsSalt, this.getName());
}
}
4.第四步:写一个登录方法吧
@RequestMapping("/user")
public class UserController {
/**
* 使用shiro进行登录认证操作
*/
@GetMapping(value = "/login")
public String login(String name, String password) {
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(name, password);
//传入一个AuthenticationToken类型的token,这里貌似UsernamePasswordToken类型的token会自动转化为AuthenticationToken
subject.login(token);
//login会直接交给shiro的自定义的Realm的认证方法处理
//登录失败的话就会抛出异常,根据异常类别来判断错误的类型,比如说:账号不存在或者密码错误:抛异常可以用try catch来抛出不同异常,但是我们也可以自定义统一异常处理类,这里就不详述了,可以看我另一个博客
/**
*
*/
return "登录成功";
}
@GetMapping("/hello")
public void run() {
System.out.println("hello");
}
}
⭐ok,这样就结束了,shiro的Security Manager会帮你管理这一切的