1、分析shiro的核心API
(1)Subjet:用户主体(登录、注销、判断授权的一些方法)(把操作交给Securitymanager)
(2)Securitymanager:安全管理器(需要关联Realm)
(3)Realm:Shiro连接数据的桥梁
2、Springboot整合shiro
(1)导入shiro与spring整合依赖,修改pom.xml
org.apache.shiro
shiro-spring
1.4.0
(2)自定义Realm类
创建一个UserRealm
类
/*
*
* 自定义Realm
* */
public class UserRealm extends AuthorizingRealm {
/*
* 执行授权逻辑
* */
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行授权逻辑");
return null;
}
/*
* 执行认证的逻辑
*
* */
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行认证的逻辑");
return null;
}
}
(3)编写shiro的配置类*****
创建ShiroConfig
类
package com.bookkeeping.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;
/*
* shiro的配置类
* */
@Configuration
public class ShiroConfig {
/*
* 1、创建ShiroFilterFactoryBean
**/
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
/*设置安全管理器*/
shiroFilterFactoryBean.setSecurityManager( securityManager );
return shiroFilterFactoryBean;
}
/*
* 2、创建DefaultWebSecurityManager
**/
@Bean(name = "securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
/*管理Realm*/
securityManager.setRealm( userRealm);
return securityManager;
}
/*
* 3、创建Realm
*
* @Bean方法返回的对象放入spring环境
* */
@Bean(name ="userRealm" )
public UserRealm getRealm(){
return new UserRealm();
}
}
(4)使用shiro内置过滤器实现页面拦截(配置ShiroConfig
)
常用过滤器
* 1、anon:无需认证(登录可以访问)
* 2、authc:必须认证才可以访问
* 3、user:如果使用rememberMe的功能,可以直接访问
* 4、perms:该资源必须得到资源权限才可以访问
* 5、role:该资源必须得到角色权限才可以访问
①、创建map集合来存储过滤器
②、设置页面被拦截后的跳转页面(目前为登录页面)
③、配置拦截页面和放行界面
必须加一个 “/”
package com.bookkeeping.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 {
/*
* 1、创建ShiroFilterFactoryBean
**/
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
/*设置安全管理器*/
shiroFilterFactoryBean.setSecurityManager( securityManager );
/*添加shiro内置过滤器(实现权限相关的拦截)
*
* 常用过滤器
* 1、anon:无需认证(登录可以访问)
* 2、authc:必须认证才可以访问
* 3、user:如果使用rememberMe的功能,可以直接访问
* 4、perms:该资源必须得到资源权限才可以访问
* 5、role:该资源必须得到角色权限才可以访问
* */
/*(--)创建map集合来存储过滤器*/
Map filterMap=new LinkedHashMap <>( );
/*拦截的页面,如果全部拦截添加 /* */
filterMap.put("/*","authc");
/*设置放行页面 必须加一个 “/” */
filterMap.put("/gologin","anon");
/*(--)修改跳转的登录页面*/
shiroFilterFactoryBean.setLoginUrl( "gologin" );
/*(--)将过滤内容放到过滤器*/
shiroFilterFactoryBean.setFilterChainDefinitionMap( filterMap );
return shiroFilterFactoryBean;
}
/*
* 2、创建DefaultWebSecurityManager
**/
@Bean(name = "securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
/*管理Realm*/
securityManager.setRealm( userRealm);
return securityManager;
}
/*
* 3、创建Realm
*
* @Bean方法返回的对象放入spring环境
* */
@Bean(name ="userRealm" )
public UserRealm getRealm(){
return new UserRealm();
}
}
(4)实现用户登录(认证)操作
①、编写登录逻辑
编写model 、.xml 、dao 、service
dao:(为通过用户名查询用户);
/*通过用户名查询用户*/
Admin selectAdminByName(@Param( "uname" ) String uname);
mapper
service serviceimpl就不写了
②、使用shiro编写认证操作
<1>、获取Subject
<2>、封装用户数据
<3>、执行登录方法
无异常——登录成功
有异常:
用户名不存在(UnknownAccountException异常)
密码错误(IncorrectCredentialsException异常)
将用户名密码传入token中
package com.bookkeeping.cj.controller;
import com.bookkeeping.cj.model.Admin;
import com.bookkeeping.cj.service.AdminService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletResponse;
import javax.xml.ws.Response;
@RestController
public class LoginController {
@Autowired
private AdminService adminService;
/*通过用户名密码登录*/
@GetMapping("adminlogin")
/*@RequestParam("uname")String uname,@RequestParam("pword")String pword,没有设置登录权限时*/
public ModelAndView loginAdmin(ModelAndView modelAndView,
@RequestParam("uname")String uname,@RequestParam("pword")String pword
){
/*
* 使用shiro编写认证操作
* */
System.out.println("用户名是:"+uname+"/密码是:"+pword);
/*1、获取Subject*/
Subject subject= SecurityUtils.getSubject();
/*2、封装用户数据 将用户名密码传入token中*/
UsernamePasswordToken token=new UsernamePasswordToken(uname,pword);
/*3、执行登录方法*/
try {
subject.login( token );
/*3.1登录成功*/
modelAndView.setViewName( "redirect:goindex" );
return modelAndView;
}catch (UnknownAccountException e){
/*3.2登录失败UnknownAccountException:用户名不存在*/
modelAndView.addObject( "msg","用户名不存在" );
modelAndView.setViewName( "login" );
return modelAndView;
}catch (IncorrectCredentialsException e){
/*3.3登录失败IncorrectCredentialsException:密码错误*/
modelAndView.addObject( "msg","密码错误" );
modelAndView.setViewName( "login" );
return modelAndView;
}
/*
Admin admin=adminService.loginAdmin( uname,pword );
if(admin!=null){
modelAndView.setViewName( "index" );
return modelAndView;
}else {
modelAndView.addObject( "msg","登录失败" );
modelAndView.setViewName( "login" );
return modelAndView;
}*/
}
}
③、进入UserRealm
执行认证的操作(只要执行登录方法就会进入执行认证的操作中)并编写Realm的判断逻辑
doGetAuthenticationInfo
:该方法为认证操作;
注入service
token.getUsername():获取前端输入的用户名
user.getPword():获取数据库中的密码
返回null时shiro底层会抛出-UnknownAccountException:用户名不存在
返回SimpleAuthenticationInfo时,该类是AuthorizationInfo的一个子类,要接收三个参数
参数1:返回login方法的一些数据(可为空)
参数2:数据库的密码
参数3:shiro的名字(可为空)
package com.bookkeeping.cj.controller.shiro;
import com.bookkeeping.cj.model.Admin;
import com.bookkeeping.cj.service.AdminService;
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;
import org.springframework.web.bind.annotation.GetMapping;
/*
*
* 自定义Realm
* */
public class UserRealm extends AuthorizingRealm {
/*
* 执行授权逻辑
* */
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行授权逻辑");
return null;
}
/*
* 执行认证的逻辑
*
* */
/*注入service*/
@Autowired
private AdminService adminService;
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken ) throws AuthenticationException {
System.out.println("执行认证的逻辑");
/*
* 编写shiro的判断逻辑,判断用户名和密码是否存在
*
* */
/*1、判断用户名是否存在*/
UsernamePasswordToken token=(UsernamePasswordToken) authenticationToken;
/*token.getUsername()为前端客户输入的用户名 查询成功返回一个用户*/
Admin user=adminService.getAdminByUname( token.getUsername() );
/*如果用户不存在*/
if(user==null){
/*返回null时shiro底层会抛出-UnknownAccountException:用户名不存在*/
return null;
}
/*2、判断密码是否存在
* user.getPword():为获取数据库中的密码;
* */
return new SimpleAuthenticationInfo( "",user.getPword(),"" );
}
}