springboot整合shiro
1 shiro是什么?
Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。
我把它理解为做登录和页面拦截的东东。
它有三个核心组件:Subject, SecurityManager 和 Realms.
1 Subject
可以理解为当前用户,我认为它不应该仅仅指人,而应该理解为当前的安全操作者。比如通过subject去验证登录等等。(shiro做实现,不需要我们编写)
2 SecurityManager
它的作用是管理所有用户的安全操作。(shiro做实现,不需要我们编写)
3 Realms
它是shiro与安全数据之间的桥梁,或者连接器。当用户需要进行登录或者授权时,在它里面进行操作。说的简单点,就是在它的方法里面进行调service方法获取数据库数据。验证用户名和密码等信息。(需要我们编写)2 好了,接下来开始说正经的了,让我们看看怎么编写以及使用的吧。。
首先,在src下建个包名为shiro,在shiro包下创建类ShiroConfig.java。在该类中写入以下内容。
package com.chenjunan.shiro; //此处别照抄
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;
import java.util.Map;
/**
* shiro配置类
*/
@Configuration
public class ShiroConfig {
/**
* 此方法用于创建ShiroFilterFactoryBean,该bean设置每个界面的访问权限
* 和设置跳转的登录页面
* 内置多个filter 每种filter有不同权限
*/
@Bean
public ShiroFilterFactoryBean gethiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager")
DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
factoryBean.setSecurityManager(securityManager);
factoryBean.setLoginUrl("login");
Map<String,String> filterMap = new LinkedHashMap<>();
filterMap.put("/add","authc");
filterMap.put("/update","authc");
filterMap.put("/login.action","anon");
factoryBean.setFilterChainDefinitionMap(filterMap);
return factoryBean;
}
//获取DefaultWebSecurityManager
@Bean(name = "defaultWebSecurityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//关联realm
securityManager.setRealm(userRealm);
return securityManager;
}
//获取自定义的realm
@Bean(name = "userRealm")
public UserRealm getRealm(){
return new UserRealm();
}
}
注: @Qualifier("userRealm") 用于通过bean的name注入指定bean
在shiro包下创建自定义的realm,我这里写UserRealm做示例。
参考代码:
package com.chenjunan.shiro;
import com.chenjunan.controller.service.UserService;
import com.chenjunan.pojo.User;
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.springframework.beans.factory.annotation.Autowired;
/**
* 自定义的realm
*/
public class UserRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
/**
* 执行授权逻辑
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行授权逻辑");
return null;
}
/**
* 执行认证逻辑
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行授权逻辑");
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) authenticationToken;
User user = userService.findByName(usernamePasswordToken.getUsername());
if(user == null)
return null; //返回为null shiro会抛出 UnknownAccountException
return new SimpleAuthenticationInfo("",user.getUser_pwd(),"");
}
}
自定义的realm需要继承AuthorizingRealm类 重载抽象方法doGetAuthorizationInfo。通过参数不同一个执行授权逻辑,一个执行认证逻辑,本次只做认证逻辑。
UsernamePasswordToken类封装表单提交的用户名和密码。
通过注入userService从数据库获取真实用户信息。dao我这里使用的mybatis框架访问的数据库.此处不做细说。
如果通过用户名从数据库未查询到数据。则返回null,shiro会抛出UnknownAccountException异常,我们在相应controller的handler中进行捕获,做出相应。
SimpleAuthenticationInfo对象用于验证密码是都正确。我们不自己判断的原因是一般数据库不明文存放密码数据,而是存放加密后的数据。一般加密不可逆。所以将数据库加密密码和用户提供的明文数据交给SimpleAuthenticationInfo对象去判断。如果密码不相匹配,抛出IncorrectCredentialsException异常,我们在controller的handler中捕获,进行响应。
controller代码如下:
package com.chenjunan.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HelloController {
@RequestMapping("/index")
public String hello(){
return "index";
}
@RequestMapping("/add")
public String add(){
return "add";
}
@RequestMapping("/update")
public String update(){
return "update";
}
@RequestMapping("/login")
public String login(){
return "login";
}
@RequestMapping("/login.action")
public String checklogin(String name, String password, Model model){
//使用shiro编写认证操作
//1.获取subject
Subject subject = SecurityUtils.getSubject();
//2.封装用户数据
UsernamePasswordToken token = new UsernamePasswordToken(name,password);
//3.执行登录方法
try {
subject.login(token); //shiro会调用realm中的认证方法
}catch (UnknownAccountException e){
//用户名不存在异常
model.addAttribute("message","用户名不存在!");
return "error";
}catch (IncorrectCredentialsException e){
//密码错误
model.addAttribute("message","密码错误!");
return "error";
}
return "index";
}
}
整个项目路径截图: spring-shiro.png注:应注意的是 subject.login(token); 这句代码,shiro底层会调用UserRealm的认证逻辑方法。去进行数据库验证。
如果用户通过验证,可穿过需要验证才能访问的页面。
如果用户已经登录,shiro会在缓存中存放相关数据。
个人觉得这篇博客关于shiro讲的很好,推荐!快速到达!
注:如有错误,请指正!感谢!
网友评论