观看 黑马的SpringBoot与Shiro整合-权限管理实战视频,根据视频学习 一步一步 实现 SpringBoot +Shiro 整合实现用户认证和权限管理。简单易懂,适合新手学习,分享给大家。
SpringBoot 与Shiro 整合实现用户认证、用户授权
Subject:用户主体(把操作交给SecurityManager)
SecurityManager:安全管理器(关联Realm)
Realm:Shiro连接数据的桥梁
pom.xml:
<!-- 导入web支持:SpringMVC开发支持,Servlet相关的程序 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- shiro 与 spring 整合依赖 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
package com.koncord.shiro;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
/**
* 自定义 Realm
* @author Administrator
*
*/
public class UserRealm extends AuthorizingRealm{
/**
* 执行授权逻辑
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("执行授权逻辑");
return null;
}
/**
* 执行认证逻辑
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("执行认证逻辑");
return null;
}
}
package com.koncord.shiro;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Configuration;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
/**
* Shiro配置类
* @author Administrator
*
*/
@Configuration
public class ShiroConfig {
/**
* 3.创建ShiroFilterFactoryBean
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean =new ShiroFilterFactoryBean();
//设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
return shiroFilterFactoryBean;
}
/**
* 2.创建 DefaultWebSecurityManager
*/
@Bean(name="securityManager")
public DefaultWebSecurityManager securityManager(@Qualifier("userRealm")UserRealm userRealm){
DefaultWebSecurityManager securityManager =new DefaultWebSecurityManager();
//关联realm
securityManager.setRealm(userRealm);
return securityManager;
}
/**
* 1.创建Realm
*/
@Bean
public UserRealm userRealm(){
return new UserRealm();
}
}
修改 配置类ShiroConfig 中的 shiroFilterFactoryBean方法:
/**
* 3.创建ShiroFilterFactoryBean
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean =new ShiroFilterFactoryBean();
//设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
//添加Shiro内置过滤器
/**
* Shiro内置过滤器,可以实现权限相关的拦截
* 常用的过滤器:
* anon:无需认证(登录)可以访问
* authc:必须认证才可以访问
* user:如果使用rememberMe的功能可以直接访问
* perms:该资源必须得到资源权限才可以访问
* role:该资源必须得到角色权限才可以访问
*/
Map<String, String> filterMap = new LinkedHashMap<String, String>();
// filterMap.put("/add", "authc");
// filterMap.put("/update", "authc");
filterMap.put("/testThymeleaf", "anon");
filterMap.put("/*", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
//设置登录跳转链接
shiroFilterFactoryBean.setLoginUrl("/toLogin");
return shiroFilterFactoryBean;
}
项目结构:
创建一个UserController类,用于测试 上面的 代码效果:
package com.koncord.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class UserController {
/**
* 测试
*/
@RequestMapping("/hello")
@ResponseBody
public String hello(){
System.out.println("UserController-hello");
return "ok";
}
/**
* 测试 thymeleaf
*/
@RequestMapping("/testThymeleaf")
public String testThymeleaf(Model model){
//将数据存入model
model.addAttribute("name", "程序猿");
//返回test.html
return "test";
}
/**
* 进入添加页面
*/
@RequestMapping("/add")
public String add(){
return "user/add";
}
/**
* 进入编辑页面
*/
@RequestMapping("/update")
public String update(){
return "user/update";
}
/**
* 进入登录页面
*/
@RequestMapping("/toLogin")
public String toLogin(){
return "login";
}
}
test.html:
<html>
<head>
<title>测试thymeleaf的使用title>
<meta name="keywords" content="keyword1,keyword2,keyword3">
<meta name="description" content="this is my page">
<meta name="content-type" content="text/html; charset=UTF-8">
head>
<body>
<h3 th:text="${name}">h3><br>
<div>进入用户添加页面:<a href="add">用户添加a>div>
<div>进入用户编辑页面:<a href="update">用户编辑a>div>
body>
html>
<html>
<head>
<title>登录title>
<meta name="keywords" content="keyword1,keyword2,keyword3">
<meta name="description" content="this is my page">
<meta name="content-type" content="text/html; charset=UTF-8">
head>
<body>
<h3>登录h3>
<h3 th:text="${msg}" style="color:red;">h3>
<form method="post" action="login">
<div>用户名:<input type="text" name="userName">div>
<div>密码:<input type="password" name="password">div>
<input type="submit" value="登录">
form>
body>
html>
package com.koncord.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.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class UserController {
/**
* 测试
*/
@RequestMapping("/hello")
@ResponseBody
public String hello(){
System.out.println("UserController-hello");
return "ok";
}
/**
* 测试 thymeleaf
*/
@RequestMapping("/testThymeleaf")
public String testThymeleaf(Model model){
//将数据存入model
model.addAttribute("name", "程序猿");
//返回test.html
return "test";
}
/**
* 进入添加页面
*/
@RequestMapping("/add")
public String add(){
return "user/add";
}
/**
* 进入编辑页面
*/
@RequestMapping("/update")
public String update(){
return "user/update";
}
/**
* 进入登录页面
*/
@RequestMapping("/toLogin")
public String toLogin(){
return "login";
}
/**
* 登录逻辑处理
*/
@RequestMapping("/login")
public String login(String userName,String password,Model model){
/**
* 使用Shiro编写认证操作
*/
//1.获取Subject
Subject subject=SecurityUtils.getSubject();
//2.封装用户数据
UsernamePasswordToken token = new UsernamePasswordToken(userName,password);
try {
//3.执行登录方法
subject.login(token);
//只要没有异常,则登录成功;有异常则登录失败
//登录成功,跳转test.html
return "redirect:/testThymeleaf";//重定向请求
} catch (UnknownAccountException e) {
//登录失败
model.addAttribute("msg", "用户不存在");
return "login";//返回页面链接
} catch (IncorrectCredentialsException e) {
//登录失败
model.addAttribute("msg", "密码错误");
return "login";
}
}
}
测试登录认证,发现没有进入认证方法,原因是 配置 shiro内置过滤器 需要把 登录 过滤掉,修改添加如下:
filterMap.put("/login", "anon");
package com.koncord.shiro;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
/**
* 自定义 Realm
* @author Administrator
*
*/
public class UserRealm extends AuthorizingRealm{
/**
* 执行授权逻辑
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("执行授权逻辑");
return null;
}
/**
* 执行认证逻辑
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("执行认证逻辑");
//假设数据库用户名和密码
String userName="admin";
String password="111111";
//编写shiro 判断逻辑,判断用户名和密码
//1.判断用户名
UsernamePasswordToken userToken=(UsernamePasswordToken) token;
if(!userToken.getUsername().equals(userName)){
//用户不存在
return null;//shiro底层会抛出 UNknowAccountException
}
//2.判断密码 第一个参数:需要返回给 subject.login方法的数据 第二个参数:密码 第三个参数:realm的名字
return new SimpleAuthenticationInfo("", password, "");
}
}
测试结果:
1.输入错误的用户名密码:zs 111111
点击登录,登录失败,提示信息如下:
2.输入正确的用户名密码 :admin 111111
点击登录,登录成功,并跳转 test.html页面:
每执行一次 登录逻辑,都会执行一次认证逻辑
pom.xml:
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>1.3.0version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<scope>runtimescope>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.1.9version>
dependency>
创建mysql数据库,新建一张简单的用户表:
插入一条数据:
其位置:src/main/rescources/目录下
## 配置数据库
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=root
#数据库连接池 druid数据源
##使用连接池类型
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
#指定实体类包名(别名包的扫描配置)
mybatis.type-aliases-package=com.koncord.model
package com.koncord.model;
public class User {
private Integer id;//主键id
private String name;//用户名
private String password;//密码
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
package com.koncord.mapper;
import com.koncord.model.User;
public interface UserMapper {
/**
* 根据用户名获取用户信息
*/
public User findUserByName(String name);
}
位置:与UserMapper.java放在一个目录下,且与UserMapper.java同名
<mapper namespace="com.koncord.mapper.UserMapper">
<select id="findUserByName" parameterType="java.lang.String" resultType="User">
select id,name,password
from sys_user
where name=#{name}
select>
mapper>
接口:UserService
package com.koncord.service;
import com.koncord.model.User;
public interface UserService {
/**
* 根据用户名获取用户信息
*/
public User findUserByName(String name);
}
实现类:UserServiceImpl
package com.koncord.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.koncord.mapper.UserMapper;
import com.koncord.model.User;
import com.koncord.service.UserService;
@Service
public class UserServiceImpl implements UserService{
//注入Mapper接口
@Autowired
private UserMapper userMapper;
/**
* 根据用户名获取用户信息
*/
@Override
public User findUserByName(String name) {
return userMapper.findUserByName(name);
}
}
如何识别 UserMapper接口:在启动类中加上@MapperScan,@MapperScan需要写上要扫描的包 (mapper接口所在的包)
package com.koncord;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* SpringBoot 启动类
* @author Administrator
*
*/
@SpringBootApplication
@MapperScan("com.koncord.mapper")
public class Application {
public static void main(String[] args){
SpringApplication.run(Application.class, args);
}
}
package com.koncord.shiro;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
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 com.koncord.model.User;
import com.koncord.service.UserService;
/**
* 自定义 Realm
* @author Administrator
*
*/
public class UserRealm extends AuthorizingRealm{
@Autowired
private UserService userService;
/**
* 执行授权逻辑
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("执行授权逻辑");
return null;
}
/**
* 执行认证逻辑
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("执行认证逻辑");
//编写shiro 判断逻辑,判断用户名和密码
//1.判断用户名
UsernamePasswordToken userToken=(UsernamePasswordToken) token;
//根据用户名获取用户信息
User user=userService.findUserByName(userToken.getUsername());
if(user == null){
//用户不存在
return null;//shiro底层会抛出 UNknowAccountException
}
//2.判断密码 第一个参数:需要返回给 subject.login方法的数据 第二个参数:数据库密码 第三个参数:realm的名字
return new SimpleAuthenticationInfo("", user.getPassword(), "");
}
}
1.输入错误的用户名,提示用户不存在
2.输入正确的用户名和错误的密码,提示密码错误
3.输入正确的用户名和密码,登录成功并跳转test.html页面
需求:用户添加只有权限达到了,才可以访问;即对用户添加做权限拦截
package com.koncord.shiro;
import java.util.LinkedHashMap;
import java.util.Map;
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配置类
* @author Administrator
*
*/
@Configuration
public class ShiroConfig {
/**
* 3.创建ShiroFilterFactoryBean
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean =new ShiroFilterFactoryBean();
//设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
//添加Shiro内置过滤器
/**
* Shiro内置过滤器,可以实现权限相关的拦截
* 常用的过滤器:
* anon:无需认证(登录)可以访问
* authc:必须认证才可以访问
* user:如果使用rememberMe的功能可以直接访问
* perms:该资源必须得到资源权限才可以访问
* role:该资源必须得到角色权限才可以访问
*/
Map<String, String> filterMap = new LinkedHashMap<String, String>();
// filterMap.put("/add", "authc");
// filterMap.put("/update", "authc");
filterMap.put("/testThymeleaf", "anon");
filterMap.put("/login", "anon");
//授权过滤器
//注意:当前授权拦截后,shiro会自动跳转到未授权页面
filterMap.put("/add", "perms[user:add]");
filterMap.put("/*", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
//设置登录跳转链接
shiroFilterFactoryBean.setLoginUrl("/toLogin");
return shiroFilterFactoryBean;
}
/**
* 2.创建 DefaultWebSecurityManager
*/
@Bean(name="securityManager")
public DefaultWebSecurityManager securityManager(@Qualifier("userRealm")UserRealm userRealm){
DefaultWebSecurityManager securityManager =new DefaultWebSecurityManager();
//关联realm
securityManager.setRealm(userRealm);
return securityManager;
}
/**
* 1.创建Realm
*/
@Bean
public UserRealm userRealm(){
return new UserRealm();
}
}
输入账号admin,密码111111,成功登录,点击“用户添加”,页面报401错误,未授权。
需要设置 未授权的页面跳转链接:
1.ShiroConfig 类的 shiroFilterFactoryBean方法中添加如下代码
//设置未授权提示页面
shiroFilterFactoryBean.setUnauthorizedUrl("/noAuth");
完整ShiroConfig代码:
package com.koncord.shiro;
import java.util.LinkedHashMap;
import java.util.Map;
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配置类
* @author Administrator
*
*/
@Configuration
public class ShiroConfig {
/**
* 3.创建ShiroFilterFactoryBean
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean =new ShiroFilterFactoryBean();
//设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
//添加Shiro内置过滤器
/**
* Shiro内置过滤器,可以实现权限相关的拦截
* 常用的过滤器:
* anon:无需认证(登录)可以访问
* authc:必须认证才可以访问
* user:如果使用rememberMe的功能可以直接访问
* perms:该资源必须得到资源权限才可以访问
* role:该资源必须得到角色权限才可以访问
*/
Map<String, String> filterMap = new LinkedHashMap<String, String>();
// filterMap.put("/add", "authc");
// filterMap.put("/update", "authc");
filterMap.put("/testThymeleaf", "anon");
filterMap.put("/login", "anon");
//授权过滤器
//注意:当前授权拦截后,shiro会自动跳转到未授权页面
filterMap.put("/add", "perms[user:add]");
filterMap.put("/*", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
//设置登录跳转链接
shiroFilterFactoryBean.setLoginUrl("/toLogin");
//设置未授权提示页面
shiroFilterFactoryBean.setUnauthorizedUrl("/noAuth");
return shiroFilterFactoryBean;
}
/**
* 2.创建 DefaultWebSecurityManager
*/
@Bean(name="securityManager")
public DefaultWebSecurityManager securityManager(@Qualifier("userRealm")UserRealm userRealm){
DefaultWebSecurityManager securityManager =new DefaultWebSecurityManager();
//关联realm
securityManager.setRealm(userRealm);
return securityManager;
}
/**
* 1.创建Realm
*/
@Bean
public UserRealm userRealm(){
return new UserRealm();
}
}
2.在UserController类中添加 未授权页面 的访问链接
/**
* 进入未授权页面
*/
@RequestMapping("/noAuth")
public String noAuth(){
return "noAuth";
}
修改UserRealm中的doGetAuthorizationInfo方法:
package com.koncord.shiro;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import com.koncord.model.User;
import com.koncord.service.UserService;
/**
* 自定义 Realm
* @author Administrator
*
*/
public class UserRealm extends AuthorizingRealm{
@Autowired
private UserService userService;
/**
* 执行授权逻辑
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("执行授权逻辑");
//给资源进行授权
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//添加资源的授权字符串
info.addStringPermission("user:add");
return info;
}
/**
* 执行认证逻辑
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("执行认证逻辑");
//编写shiro 判断逻辑,判断用户名和密码
//1.判断用户名
UsernamePasswordToken userToken=(UsernamePasswordToken) token;
//根据用户名获取用户信息
User user=userService.findUserByName(userToken.getUsername());
if(user == null){
//用户不存在
return null;//shiro底层会抛出 UNknowAccountException
}
//2.判断密码 第一个参数:需要返回给 subject.login方法的数据 第二个参数:数据库密码 第三个参数:realm的名字
return new SimpleAuthenticationInfo("", user.getPassword(), "");
}
}
上面2的资源授权是写死的,实际开发中是应该是变得更加灵活,这里进行改造程序,把它和数据库进行一个简单的连接。
package com.koncord.model;
public class User {
private Integer id;//主键id
private String name;//用户名
private String password;//密码
private String perms;//权限
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPerms() {
return perms;
}
public void setPerms(String perms) {
this.perms = perms;
}
}
获取当前用户信息,查询数据库获取对应的授权字符串,添加这个授权字符串到SimpleAuthorizationInfo 对象中。
代码如下:
package com.koncord.shiro;
import java.lang.reflect.InvocationTargetException;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import com.koncord.model.User;
import com.koncord.service.UserService;
/**
* 自定义 Realm
* @author Administrator
*
*/
public class UserRealm extends AuthorizingRealm{
@Autowired
private UserService userService;
/**
* 执行授权逻辑
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("执行授权逻辑");
//给资源进行授权
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//添加资源的授权字符串
//info.addStringPermission("user:add");
//导数据库查询当前登录用户的授权字符串
//获取当前登录用户
Subject subject=SecurityUtils.getSubject();
User user = (User) subject.getPrincipal();
User sbUser=userService.findUserByName(user.getName());
info.addStringPermission(sbUser.getPerms());
return info;
}
/**
* 执行认证逻辑
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("执行认证逻辑");
//编写shiro 判断逻辑,判断用户名和密码
//1.判断用户名
UsernamePasswordToken userToken=(UsernamePasswordToken) token;
//根据用户名获取用户信息
User user=userService.findUserByName(userToken.getUsername());
if(user == null){
//用户不存在
return null;//shiro底层会抛出 UNknowAccountException
}
//2.判断密码 第一个参数:需要返回给 subject.login方法的数据 第二个参数:数据库密码 第三个参数:realm的名字
return new SimpleAuthenticationInfo(user, user.getPassword(), "");
}
}
两个用户进行测试
1.用户admin登录,admin用户有 用户添加 权限,没有 用户编辑 权限;
2.用户zhangsan登录,zhangsan用户没有 用户添加 权限,有 用户编辑 权限。
<dependency>
<groupId>com.github.theborakompanionigroupId>
<artifactId>thymeleaf-extras-shiroartifactId>
<version>2.0.0version>
dependency>
在ShiroConfig类里面添加 getShiroDialect方法:
/**
* 配置ShiroDialect,用于thymeleaf和shiro标签配合使用
*/
@Bean
public ShiroDialect getShiroDialect(){
return new ShiroDialect();
}
需求:不同的用户,看到的页面内容不同。
这里需要用到shiro标签 shiro:hasPermission
修改test.html页面:
<html>
<head>
<title>测试thymeleaf的使用title>
<meta name="keywords" content="keyword1,keyword2,keyword3">
<meta name="description" content="this is my page">
<meta name="content-type" content="text/html; charset=UTF-8">
head>
<body>
<h3 th:text="${name}">h3><br>
<div shiro:hasPermission="user:add">
进入用户添加页面:<a href="add">用户添加a>
div>
<div shiro:hasPermission="user:update">
进入用户编辑页面:<a href="update">用户编辑a>
div>
<a href="toLogin">登录a>
body>
html>
认证逻辑与授权逻辑 执行次数:
根据演示视频,可以看出:
1.每次登录时执行一次认证逻辑 和 两次授权逻辑(和 ShiroConfig中配置 授权过滤器 个数有关 );
2.访问 单个授权过滤器 配置的链接时,执行一次授权逻辑;
3.访问非授权过滤器配置链接时,不进入授权逻辑。
点击此处下载