Java安全框架——Shiro的使用详解(附springboot整合Shiro的demo)
导入依赖
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.7.1</version></dependency><!-- configure logging --><!-- https://mvnrepository.com/artifact/org.slf4j/jcl-over-slf4j --><dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>2.0.0-alpha1</version></dependency><dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>2.0.0-alpha1</version></dependency><dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version></dependency>
配置log4j.properties
log4j.rootLogger=INFO, stdoutlog4j.appender.stdout=org.apache.log4j.ConsoleAppenderlog4j.appender.stdout.layout=org.apache.log4j.PatternLayoutlog4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n# General Apache librarieslog4j.logger.org.apache=WARN# Springlog4j.logger.org.springframework=WARN# Default Shiro logginglog4j.logger.org.apache.shiro=INFO# Disable verbose logginglog4j.logger.org.apache.shiro.util.ThreadContext=WARNlog4j.logger.org.apache.shiro.cache.ehcache.EhCache=WARN
配置Shiro.ini(在IDEA中需要导入ini插件)
[users]# user ’root’ with password ’secret’ and the ’admin’ roleroot = secret, admin# user ’guest’ with the password ’guest’ and the ’guest’ roleguest = guest, guest# user ’presidentskroob’ with password ’12345’ ('That’s the same combination on# my luggage!!!' ;)), and role ’president’presidentskroob = 12345, president# user ’darkhelmet’ with password ’ludicrousspeed’ and roles ’darklord’ and ’schwartz’darkhelmet = ludicrousspeed, darklord, schwartz# user ’lonestarr’ with password ’vespa’ and roles ’goodguy’ and ’schwartz’lonestarr = vespa, goodguy, schwartz# -----------------------------------------------------------------------------# Roles with assigned permissions## Each line conforms to the format defined in the# org.apache.shiro.realm.text.TextConfigurationRealm#setRoleDefinitions JavaDoc# -----------------------------------------------------------------------------[roles]# ’admin’ role has all permissions, indicated by the wildcard ’*’admin = *# The ’schwartz’ role can do anything (*) with any lightsaber:schwartz = lightsaber:*# The ’goodguy’ role is allowed to ’drive’ (action) the winnebago (type) with# license plate ’eagle5’ (instance specific id)goodguy = winnebago:drive:eagle5
快速入门实现类 quickStart.java
import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.*;import org.apache.shiro.config.IniSecurityManagerFactory;import org.apache.shiro.mgt.DefaultSecurityManager;import org.apache.shiro.realm.text.IniRealm;import org.apache.shiro.session.Session;import org.apache.shiro.subject.Subject;import org.apache.shiro.util.Factory;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class quickStart { private static final transient Logger log = LoggerFactory.getLogger(quickStart.class); /*Shiro三大对象:Subject: 用户SecurityManager:管理所有用户Realm: 连接数据 */ public static void main(String[] args) {// 创建带有配置的Shiro SecurityManager的最简单方法// realms, users, roles and permissions 是使用简单的INI配置。// 我们将使用可以提取.ini文件的工厂来完成此操作,// 返回一个SecurityManager实例:// 在类路径的根目录下使用shiro.ini文件// (file:和url:前缀分别从文件和url加载)://Factory<SecurityManager> factory = new IniSecurityManagerFactory('classpath:shiro.ini');//SecurityManager securityManager = factory.getInstance();DefaultSecurityManager securityManager = new DefaultSecurityManager();IniRealm iniRealm = new IniRealm('classpath:shiro.ini');securityManager.setRealm(iniRealm);// 对于这个简单的示例快速入门,请使SecurityManager// 可作为JVM单例访问。大多数应用程序都不会这样做// 而是依靠其容器配置或web.xml进行// webapps。这超出了此简单快速入门的范围,因此// 我们只做最低限度的工作,这样您就可以继续感受事物.SecurityUtils.setSecurityManager(securityManager);// 现在已经建立了一个简单的Shiro环境,让我们看看您可以做什么:// 获取当前用户对象 SubjectSubject currentUser = SecurityUtils.getSubject();// 使用Session做一些事情(不需要Web或EJB容器!!!Session session = currentUser.getSession();//通过当前用户拿到Sessionsession.setAttribute('someKey', 'aValue');String value = (String) session.getAttribute('someKey');if (value.equals('aValue')) { log.info('Retrieved the correct value! [' + value + ']');}// 判断当前用户是否被认证if (!currentUser.isAuthenticated()) { //token : 令牌,没有获取,随机 UsernamePasswordToken token = new UsernamePasswordToken('lonestarr', 'vespa'); token.setRememberMe(true); // 设置记住我 try {currentUser.login(token);//执行登陆操作 } catch (UnknownAccountException uae) {//打印出 用户名log.info('There is no user with username of ' + token.getPrincipal()); } catch (IncorrectCredentialsException ice) {//打印出 密码log.info('Password for account ' + token.getPrincipal() + ' was incorrect!'); } catch (LockedAccountException lae) {log.info('The account for username ' + token.getPrincipal() + ' is locked. ' +'Please contact your administrator to unlock it.'); } // ... 在此处捕获更多异常(也许是针对您的应用程序的自定义异常? catch (AuthenticationException ae) {//unexpected condition? error? }}//say who they are://print their identifying principal (in this case, a username):log.info('User [' + currentUser.getPrincipal() + '] logged in successfully.');//test a role:if (currentUser.hasRole('schwartz')) { log.info('May the Schwartz be with you!');} else { log.info('Hello, mere mortal.');}//test a typed permission (not instance-level)if (currentUser.isPermitted('lightsaber:wield')) { log.info('You may use a lightsaber ring. Use it wisely.');} else { log.info('Sorry, lightsaber rings are for schwartz masters only.');}//a (very powerful) Instance Level permission:if (currentUser.isPermitted('winnebago:drive:eagle5')) { log.info('You are permitted to ’drive’ the winnebago with license plate (id) ’eagle5’. ' + 'Here are the keys - have fun!');} else { log.info('Sorry, you aren’t allowed to drive the ’eagle5’ winnebago!');}//all done - log out!currentUser.logout();//注销System.exit(0);//退出 }}
启动测试
SpringBoot-Shiro整合(最后会附上完整代码)前期工作
导入shiro-spring整合包依赖
<!-- shiro-spring整合包 --><dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.7.1</version></dependency>
跳转的页面index.html
<html lang='en' xmlns:th='http://www.w3.org/1999/xhtml'><head> <meta charset='UTF-8'> <title>首页</title></head><body><h1>首页</h1><p th:text='${msg}'></p><a th:href='https://www.haobala.com/bcjs/@{/user/add}' rel='external nofollow' rel='external nofollow' rel='external nofollow' >add</a>| <a th:href='https://www.haobala.com/bcjs/@{/user/update}' rel='external nofollow' rel='external nofollow' rel='external nofollow' >update</a></body></html>
add.html
<!DOCTYPE html><html lang='en'><head> <meta charset='UTF-8'> <title>add</title></head><body><p>add</p></body></html>
update.html
<!DOCTYPE html><html lang='en'><head> <meta charset='UTF-8'> <title>update</title></head><body><p>update</p></body></html>
编写shiro的配置类ShiroConfig.java
package com.example.config;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;@Configurationpublic class ShiroConfig { //3. ShiroFilterFactoryBean @Bean public ShiroFilterFactoryBean getshiroFilterFactoryBean(@Qualifier('SecurityManager') DefaultWebSecurityManager defaultWebSecurityManager){ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();//设置安全管理器factoryBean.setSecurityManager(defaultWebSecurityManager);return factoryBean; } //2.创建DefaultWebSecurityManager @Bean(name = 'SecurityManager') public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier('userRealm') UserRealm userRealm){DefaultWebSecurityManager SecurityManager=new DefaultWebSecurityManager();//3.关联RealmSecurityManager.setRealm(userRealm);return SecurityManager; } //1.创建Realm对象 @Bean(name = 'userRealm') public UserRealm userRealm(){return new UserRealm(); }}
编写UserRealm.java
package com.example.config;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;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; }}
编写controller测试环境是否搭建好
package com.example.controller;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.RequestMapping;@Controllerpublic class MyController { @RequestMapping({'/','/index'}) public String index(Model model){model.addAttribute('msg','hello,shiro');return 'index'; } @RequestMapping('/user/add') public String add(){return 'user/add'; } @RequestMapping('/user/update') public String update(){return 'user/update'; }}
实现登录拦截
在ShiroConfig.java文件中添加拦截
Map<String,String> filterMap = new LinkedHashMap<>();//对/user/*下的文件只有拥有authc权限的才能访问filterMap.put('/user/*','authc');//将Map存放到ShiroFilterFactoryBean中factoryBean.setFilterChainDefinitionMap(filterMap);
这样,代码跑起来,你点击add或者update就会出现404错误,这时候,我们再继续添加,让它跳转到我们自定义的登录页
添加登录拦截到登录页
//需进行权限认证时跳转到toLoginfactoryBean.setLoginUrl('/toLogin');//权限认证失败时跳转到unauthorizedfactoryBean.setUnauthorizedUrl('/unauthorized');
login.html
<!DOCTYPE html><html lang='en'><head> <meta charset='UTF-8'> <title>登录</title></head><body><form action=''> 用户名:<input type='text' name='username'><br> 密码:<input type='text' name='password'><br> <input type='submit'></form></body></html>
视图跳转添加一个login页面跳转
@RequestMapping('/toLogin') public String login(){return 'login'; }
上面,我们已经成功拦截了,现在我们来实现用户认证
首先,我们需要一个登录页面
login.html
<!DOCTYPE html><html lang='en' xmlns:th='http://www.w3.org/1999/xhtml'><head> <meta charset='UTF-8'> <title>登录</title></head><body><p th:text='${msg}' style='color: red'></p><form th:action='@{/login}'> 用户名:<input type='text' name='username'><br> 密码:<input type='text' name='password'><br> <input type='submit'></form></body></html>
其次,去controller编写跳转到登录页面
@RequestMapping('/login') public String login(String username,String password,Model model){//获得当前的用户Subject subject = SecurityUtils.getSubject();//封装用户数据UsernamePasswordToken taken = new UsernamePasswordToken(username,password);try{//执行登陆操作,没有发生异常就说明登陆成功 subject.login(taken); return 'index';}catch (UnknownAccountException e){ model.addAttribute('msg','用户名错误'); return 'login';}catch (IncorrectCredentialsException e){ model.addAttribute('msg','密码错误'); return 'login';} }
最后去UserRealm.java配置认证
//认证 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {System.out.println('认证');String name = 'root';String password = '123456';UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;if (!userToken.getUsername().equals(name)){ return null;//抛出异常 用户名错误那个异常}//密码认证,shiro自己做return new SimpleAuthenticationInfo('',password,''); }
运行测试,成功!!!
附上最后的完整代码pom.xml引入的依赖
pom.xml
<?xml version='1.0' encoding='UTF-8'?><project xmlns='http://maven.apache.org/POM/4.0.0' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:schemaLocation='http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd'> <modelVersion>4.0.0</modelVersion> <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.4.4</version><relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>springboot-08-shiro</artifactId> <version>0.0.1-SNAPSHOT</version> <name>springboot-08-shiro</name> <description>Demo project for Spring Boot</description> <properties><java.version>1.8</java.version> </properties> <dependencies><!-- shiro-spring整合包 --><dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.7.1</version></dependency><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-starter-test</artifactId> <scope>test</scope></dependency> </dependencies> <build><plugins> <plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId> </plugin></plugins> </build></project>
静态资源
index.html
<html lang='en' xmlns:th='http://www.w3.org/1999/xhtml'><head> <meta charset='UTF-8'> <title>首页</title></head><body><h1>首页</h1><p th:text='${msg}'></p><a th:href='https://www.haobala.com/bcjs/@{/user/add}' rel='external nofollow' rel='external nofollow' rel='external nofollow' >add</a>| <a th:href='https://www.haobala.com/bcjs/@{/user/update}' rel='external nofollow' rel='external nofollow' rel='external nofollow' >update</a></body></html>
login.html
<!DOCTYPE html><html lang='en' xmlns:th='http://www.w3.org/1999/xhtml'><head> <meta charset='UTF-8'> <title>登录</title></head><body><p th:text='${msg}' style='color: red'></p><form th:action='@{/login}'> 用户名:<input type='text' name='username'><br> 密码:<input type='text' name='password'><br> <input type='submit'></form></body></html>
add.html
<!DOCTYPE html><html lang='en'><head> <meta charset='UTF-8'> <title>add</title></head><body><p>add</p></body></html>
update.html
<!DOCTYPE html><html lang='en'><head> <meta charset='UTF-8'> <title>update</title></head><body><p>update</p></body></html>
controller层
MyController.java
package com.example.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;@Controllerpublic class MyController { @RequestMapping({'/','/index'}) public String index(Model model){model.addAttribute('msg','hello,shiro');return 'index'; } @RequestMapping('/user/add') public String add(){return 'user/add'; } @RequestMapping('/user/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){//获得当前的用户Subject subject = SecurityUtils.getSubject();//封装用户数据UsernamePasswordToken taken = new UsernamePasswordToken(username,password);try{//执行登陆操作,没有发生异常就说明登陆成功 subject.login(taken); return 'index';}catch (UnknownAccountException e){ model.addAttribute('msg','用户名错误'); return 'login';}catch (IncorrectCredentialsException e){ model.addAttribute('msg','密码错误'); return 'login';} }}
config文件
ShiroConfig.java
package com.example.config;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;@Configurationpublic class ShiroConfig { //4. ShiroFilterFactoryBean @Bean public ShiroFilterFactoryBean getshiroFilterFactoryBean(@Qualifier('SecurityManager') DefaultWebSecurityManager defaultWebSecurityManager){ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();//5. 设置安全管理器factoryBean.setSecurityManager(defaultWebSecurityManager);/* shiro内置过滤器 anon无需授权、登录就可以访问,所有人可访。 authc 需要登录授权才能访问。 authcBasicBasic HTTP身份验证拦截器 logout退出拦截器。退出成功后,会 redirect到设置的/URI noSessionCreation不创建会话连接器 perms授权拦截器,拥有对某个资源的权限才可访问 port端口拦截器 restrest风格拦截器 roles角色拦截器,拥有某个角色的权限才可访问 sslssl拦截器。通过https协议才能通过 user用户拦截器,需要有remember me功能方可使用 */Map<String,String> filterMap = new LinkedHashMap<>();//对/user/*下的文件只有拥有authc权限的才能访问filterMap.put('/user/*','authc');//将Map存放到ShiroFilterFactoryBean中factoryBean.setFilterChainDefinitionMap(filterMap);//需进行权限认证时跳转到toLoginfactoryBean.setLoginUrl('/toLogin');//权限认证失败时跳转到unauthorizedfactoryBean.setUnauthorizedUrl('/unauthorized');return factoryBean; } //2.创建DefaultWebSecurityManager @Bean(name = 'SecurityManager') public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier('userRealm') UserRealm userRealm){DefaultWebSecurityManager SecurityManager=new DefaultWebSecurityManager();//3.关联RealmSecurityManager.setRealm(userRealm);return SecurityManager; } //1.创建Realm对象 @Bean(name = 'userRealm') public UserRealm userRealm(){return new UserRealm(); }}
UserRealm.java
package com.example.config;import org.apache.shiro.authc.*;import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.subject.PrincipalCollection;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('认证');String name = 'root';String password = '123456';UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;if (!userToken.getUsername().equals(name)){ return null;//抛出异常 用户名错误那个异常}//密码认证,shiro自己做return new SimpleAuthenticationInfo('',password,''); }}
但是,我们在用户认证这里,真实情况是从数据库中取的,所以,我们接下来去实现一下从数据库中取出数据来实现用户认证
Shiro整合mybatis前期工作
在前面导入的依赖中,继续添加以下依赖
<!-- mysql --><dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId></dependency><!-- log4j --><dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version></dependency><!-- 数据源Druid --><dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.5</version></dependency><!-- 引入mybatis --><dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.4</version></dependency><!-- lombok --><dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId></dependency>
导入了mybatis和Druid,就去application.properties配置一下和DruidDruid
spring: datasource: username: root password: 123456 url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8 driver-class-name: com.mysql.cj.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource # 自定义数据源 #Spring Boot 默认是不注入这些属性值的,需要自己绑定 #druid 数据源专有配置 initialSize: 5 minIdle: 5 maxActive: 20 maxWait: 60000 timeBetweenEvictionRunsMillis: 60000 minEvictableIdleTimeMillis: 300000 validationQuery: SELECT 1 FROM DUAL testWhileIdle: true testOnBorrow: false testOnReturn: false poolPreparedStatements: true #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入 #如果允许时报错 java.lang.ClassNotFoundException: org.apache.log4j.Priority #则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4j filters: stat,wall,log4j maxPoolPreparedStatementPerConnectionSize: 20 useGlobalDataSourceStat: true connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
mybatis
mybatis: type-aliases-package: com.example.pojo mapper-locations: classpath:mapper/*.xml
连接数据库编写实体类
package com.example.pojo;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;@Data@AllArgsConstructor@NoArgsConstructorpublic class User {private Integer id;private String name;private String pwd;}
编写mapper
package com.example.mapper;import com.example.pojo.User;import org.apache.ibatis.annotations.Mapper;import org.springframework.stereotype.Repository;@Repository@Mapperpublic interface UserMapper { public User getUserByName(String name);}
编写mapper.xml
<?xml version='1.0' encoding='UTF8' ?><!DOCTYPE mapperPUBLIC '-//mybatis.org//DTD Mapper 3.0//EN''http://mybatis.org/dtd/mybatis-3-mapper.dtd'><mapper namespace='com.example.mapper.UserMapper'> <select parameterType='String' resultType='User'>select * from mybatis.user where name=#{name} </select></mapper>
编写service
package com.example.service;import com.example.pojo.User;public interface UserService { public User getUserByName(String name);}
package com.example.service;import com.example.mapper.UserMapper;import com.example.pojo.User;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;@Servicepublic class UserServiceImpl implements UserService{ @Autowired UserMapper userMapper; @Override public User getUserByName(String name) {return userMapper.getUserByName(name); }}
使用数据库中的数据
修改UserRealm.java即可
package com.example.config;import com.example.pojo.User;import com.example.service.UserService;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;public class UserRealm extends AuthorizingRealm { @Autowired UserService userService; //授权 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {System.out.println('授权');return null; } //认证 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {System.out.println('认证');UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;//连接真实的数据库User user = userService.getUserByName(userToken.getUsername());if (user==null){ return null;//抛出异常 用户名错误那个异常}//密码认证,shiro自己做return new SimpleAuthenticationInfo('',user.getPwd(),''); }}认证搞完了,我们再来看看授权
在ShiroConfig.java文件加入授权,加入这行代码: filterMap.put('/user/add','perms[user:add]');//只有拥有user:add权限的人才能访问add,注意授权的位置在认证前面,不然授权会认证不了;
运行测试:add页面无法访问
授权同理:filterMap.put('/user/update','perms[user:update]');//只有拥有user:update权限的人才能访问update
自定义一个未授权跳转页面
在ShiroConfig.java文件设置未授权时跳转到unauthorized页面,加入这行代码:factoryBean.setUnauthorizedUrl('/unauthorized'); 2. 去Mycontroller写跳转未授权页面
@RequestMapping('/unauthorized') @ResponseBody//懒得写界面,返回一个字符串 public String unauthorized(){return '没有授权,无法访问'; }
运行效果:
从数据库中接受用户的权限,进行判断
在数据库中添加一个属性perms,相应的实体类也要修改
修改UserRealm.java
package com.example.config;import com.example.pojo.User;import com.example.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 AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {System.out.println('授权');SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();//没有使用数据库,直接自己设置的用户权限,给每个人都设置了,现实中要从数据库中取//info.addStringPermission('user:add');//从数据库中得到权限信息//获得当前登录的对象Subject subject = SecurityUtils.getSubject();//拿到User对象,通过getPrincipal()获得User currentUser = (User) subject.getPrincipal();//设置当前用户的权限info.addStringPermission(currentUser.getPerms());return info; } //认证 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {System.out.println('认证');UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;//连接真实的数据库User user = userService.getUserByName(userToken.getUsername());if (user==null){ return null;//抛出异常 用户名错误那个异常}//密码认证,shiro自己做return new SimpleAuthenticationInfo(user,user.getPwd(),''); }}
有了授权后,就又出现了一个问题,我们是不是要让用户没有权限的东西,就看不见呢?这时候,就出现了Shiro-thymeleaf整合
Shiro-thymeleaf整合导入整合的依赖
<!-- 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>
在ShiroConfig整合ShiroDialect
//整合ShiroDialect: 用来整合 shiro thymeleaf @Bean public ShiroDialect getShiroDialect(){return new ShiroDialect(); }
修改index页面
<html lang='en' xmlns:th='http://www.thymeleaf.org' xmlns:shiro='http://www.thymeleaf.org/thymeleaf-extras-shiro'><!-- 三个命名空间xmlns:th='http://www.thymeleaf.org'xmlns:sec='http://www.thymeleaf.org/extras/spring-security'xmlns:shiro='http://www.thymeleaf.org/thymeleaf-extras-shiro'--><head> <meta charset='UTF-8'> <title>首页</title></head><body><h1>首页</h1><p th:text='${msg}'></p><!--判断是否有用户登录,如果有就不显示登录按钮--><div th:if='${session.loginUser==null}'> <a th:href='https://www.haobala.com/bcjs/@{/toLogin}' rel='external nofollow' >登录</a></div><div shiro:hasPermission='user:add'> <a th:href='https://www.haobala.com/bcjs/@{/user/add}' rel='external nofollow' rel='external nofollow' rel='external nofollow' >add</a></div><div shiro:hasPermission='user:update'> <a th:href='https://www.haobala.com/bcjs/@{/user/update}' rel='external nofollow' rel='external nofollow' rel='external nofollow' >update</a></div></body></html>
判断是否有用户登录
//这个是整合shiro和thymeleaf用到的,让登录按钮消失的判断Subject subject = SecurityUtils.getSubject();Session session = subject.getSession();session.setAttribute('loginUser', user);
测试
以上就是Java安全框架——Shiro的使用详解(附springboot整合Shiro的demo)的详细内容,更多关于Java安全框架——Shiro的资料请关注好吧啦网其它相关文章!
相关文章:
1. 匹配模式 - XSL教程 - 42. CSS3中Transition属性详解以及示例分享3. ASP中if语句、select 、while循环的使用方法4. ASP中格式化时间短日期补0变两位长日期的方法5. 将properties文件的配置设置为整个Web应用的全局变量实现方法6. set rs=conn.execute,set rs=server.createobject(“ADODB.recordset”)的性能对比7. jsp实现登录验证的过滤器8. jsp cookie+session实现简易自动登录9. asp读取xml文件和记数10. uni-app低成本封装一个取色器组件的简单方法