权限
package com.irhema.shiro;
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
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;
@Configuration
public class ShiroConfig {
/**
* shiroFilterFactoryBean
* 使用@Bean,将getShiroFilterFactoryBean()方法返回的bean对象装入到spring容器中(放入spring环境中)。
* 好让spring知道我们创建了shiroFilterFactoryBean这样一个对象。否则该方法或该 对象将失效,不起作用
/
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
//内置有很多过滤器来进行url的拦截
//设置安全管理器,可通过注解@Qualifier查找securityManager的bean并注入
shiroFilterFactoryBean.setSecurityManager(securityManager);
/*
* 添加shiro内置过滤器,实现权限相关的拦截器
* 常用的过滤器
* anon 全面开放
* authc 需要认证
* page 使用remember me功能才能访问
* perms 得到该资源权限才能访问 授权拦截器
* role 得到角色权限才能访问 授权拦截器
/
Map<String,String> filterMap=new LinkedHashMap<String, String>();
/*
* 授权配置
/
filterMap.put("/user/add","perms[user:add]"); /为添加设置权限拦截--数据库中lmj用户有添加权限--/
shiroFilterFactoryBean.setUnauthorizedUrl("/user/unAuth");
filterMap.put("/user/update","perms[user:update]"); /为更新设置权限拦截--数据库中admin用户有添加权限--/
//filterMap.put("/user/add","authc");
// filterMap.put("/user/update","authc");
/**
* 认证
/
filterMap.put("/index","anon");
filterMap.put("/user/select","anon");
filterMap.put("/user/login","anon");
filterMap.put("/user/","authc");
//使用通配符 filterMap.put("/page/","authc"); 让user下面的所有资源都需要认证后才能放行
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
/**
* 自定义shirio默认跳转的登陆页面
/
shiroFilterFactoryBean.setLoginUrl("/user/toLogin");
return shiroFilterFactoryBean;
}
/*
* 创建defaultsecurityManager
* 可通过@Qualifier注解拿到getRealm()方法返回的bean作为参数传入getDefaultWebSecurityManager()方法中
/
@Bean(name="securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
//关联realm
securityManager.setRealm(userRealm);
return securityManager;
}
/*
* 创建realm
* @Bean注解的含义是让该方法返回的对象注入到spring的环境中,(丢进spring容器里),
* 方便被defaultsecurityManager所调用
*/
@Bean(name="userRealm")
public UserRealm getRealm(){
return new UserRealm();
}
/**
* 配置ShiroDialect,用于Shiro和thymeleaf标签配合使用
* @return
*/
@Bean
public ShiroDialect shiroDialect(){
return new ShiroDialect();
}
}
-----------------------------UserRealm ---------------------
package com.irhema.shiro;
import com.irhema.domain.User;
import com.irhema.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
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;
public class UserRealm extends AuthorizingRealm {
@Autowired
UserService userService;
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token= (UsernamePasswordToken) authenticationToken;
User user=userService.findByName(token.getUsername());
if (user==null){
return null;
}
//这里传的是user对象,不是"user字符串",这样写会报类型转换错误异常SimpleAuthenticationInfo(“user”,user.getPassword(),"");
return new SimpleAuthenticationInfo(user,user.getPassword(),"");
/**
* 无数据库版本
/
/ String name="lmj";
String password="123";
//将传来的参数转为UsernamePasswordToken
UsernamePasswordToken token= (UsernamePasswordToken) authenticationToken;
if (!token.getUsername().equals(name)){
return null;
}
//返回AuthenticationInfo的子类SimpleAuthenticationInfo即可
(第一个参数是返回给login的信息,它是一个当事人对象Principal,可以填user,方便传到doGetAuthorizationInfo中,
第二个是从数据库取来的密码
// shiro会自动去做密码是否匹配的判断,第三个参数是shiro的名字,我们可以留空,第二个参数一定要是数据库 的密码)
return new SimpleAuthenticationInfo("",password,"");
*/
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
/**
* 使用AuthorizationInfo接口的子类SimpleAuthorizationInfo
* 为用户授予user:add添加的权限
*/
SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
/**
* 数据库中取出权限字符串
*/
Subject subject= SecurityUtils.getSubject();
/**
* //Principal包含用户的标识和用户的所属角色的对象---专业术语叫--当事人,委托人 ,拿到当事人对象
* 它是认证是传过来的,故需要将原来的doGetAuthorizationInfo()方法中的
* return new SimpleAuthenticationInfo("",user.getPassword(),"");
*
* 更改为:
* return new SimpleAuthenticationInfo("user",user.getPassword(),"");
*/
User user= (User) subject.getPrincipal();
User dbUser=userService.findById(user.getId());
info.addStringPermission(dbUser.getPerms());
return info;
}
}
-----------------index
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>
<!-- 相关数据库依赖-->
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.17</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
<!-- thymeleaf对shiro的扩展坐标。即thymeleaf标签对shiro框架的支持-->
<!-- https://mvnrepository.com/artifact/com.github.theborakompanioni/thymeleaf-extras-shiro -->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<!-- 配置将哪些资源文件(静态文件/模板文件/mapper文件)加载到tomcat输出目录里 -->
<resources>
<resource>
<directory>src/main/java</directory><!--java文件的路径-->
<includes>
<include>**/*.java</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
</build>
package com.irhema.controller;
import org.apache.shiro.SecurityUtils;
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;
import java.util.Map;
@Controller
@RequestMapping("/user")
public class UserController {
//因为我们使用了springmvc的全局拦截功能,所以使用超链接跳转就不行了。我们需要写controller。
//让它经过controller来进行资源的访问。相当于controller里配置的资源访问路径是springmvc认为合法的
//允许放行的资源路径
@RequestMapping("/add")
public String add(){
return "add";
}
@RequestMapping("/update")
public String update(){
return "update";
}
@RequestMapping("/toLogin")
public String tologin(){
return "login";
}
@RequestMapping("/select")
public String select(Map<String,Object> map){
map.put("msg","hello");
return "select";
}
@RequestMapping("/login")
public String login(String username, String password, Map<String,Object> map){
map.put("msg","登陆成功:"+" "+username+" "+password);
/**
*使用shiro编写认证操作
*/
// todo 获取subject(通过securityUtil拿到subject用户主题)
Subject subject= SecurityUtils.getSubject();
// todo 封装用户数据(将用户名,密码装进usernamepasstoken对象里面)
UsernamePasswordToken token=new UsernamePasswordToken(username,password);
try{
/**
* 这里shiro会将login的处理流程交给UserRealm
* 我们在userRealm的doGetAuthenticationInfo和doGetAuthorizationInfo里写我们的业务逻辑就可以了
* 只要执行了subject.login(token);方法,它就一定会来到认证逻辑这里 及上面的两个方法
*/
subject.login(token);
return "index";
//无异常,则说明登陆成功
}catch (UnknownAccountException e){
// e.printStackTrace();
//登陆失败,用户名不存在
map.put("msg","用户名不存在");
//不加redirect重定向,程序会认为这是一个页面,我们需要的它是一个请求路径
System.out.println("用户名不存在");
return "index";
}catch (IncorrectCredentialsException e){
map.put("msg","密码错误");
System.out.println("密码错误");
return "index";
}catch (Exception e){
System.out.println("用户名或密码为空");
return null;
}
}
@RequestMapping("/unAuth")
public String unAuth(Map<String,Object> map){
map.put("msg","请去授权");
return "unAuth";
}
}

浙公网安备 33010602011771号