Shiro 简介
Apache Shiro是一个强大且易用的 Java 安全框架,执行身份验证、授权、密码和会话管理 三个核心组件:Subject, SecurityManager 和 Realms Subject代表了当前用户的安全操作 SecurityManager管理所有用户的安全操作,是Shiro框架的核心,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。 Realm充当了Shiro与应用安全数据间的[桥梁]或者[连接器]。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。 Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。Shiro快速入门
导入依赖
<dependency> <groupId> org.apache.shiro </groupId> <artifactId> shiro-core </artifactId> <version> 1.7.1 </version> </dependency> <!-- configure logging --> <!-- https://mvnrepository测试数据/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 , stdout log4j . appender . stdout = org . apache . log4j . ConsoleAppender log4j . appender . stdout . layout = org . apache . log4j . PatternLayout log4j . appender . stdout . layout . ConversionPattern =% d % p [% c ] - % m % n # General Apache libraries log4j . logger . org . apache = WARN # Spring log4j . logger . org . springframework = WARN # Default Shiro logging log4j . logger . org . apache . shiro = INFO # Disable verbose logging log4j . logger . org . apache . shiro . util . ThreadContext = WARN log4j . logger . org . apache . shiro . cache . ehcache . EhCache = WARN配置Shiro.ini(在IDEA中需要导入ini插件)
[ users ] # user 'root' with password 'secret' and the 'admin' role root = secret , admin # user 'guest' with the password 'guest' and the 'guest' role guest = 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环境,让我们看看您可以做什么: // 获取当前用户对象 Subject Subject currentUser = SecurityUtils . getSubject (); // 使用Session做一些事情(不需要Web或EJB容器!!! Session session = currentUser . getSession (); //通过当前用户拿到Session session . 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
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 ; @Configuration public 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.关联Realm SecurityManager . 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 ; @Controller public 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错误,这时候,我们再继续添加,让它跳转到我们自定义的登录页
添加登录拦截到登录页
//需进行权限认证时跳转到toLogin factoryBean . setLoginUrl ( "/toLogin" ); //权限认证失败时跳转到unauthorized factoryBean . 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://HdhCmsTestw3.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://HdhCmsTestw3.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://HdhCmsTestw3.org/1999/xhtml" > <head> <meta charset = "UTF-8" > <title> 首页 </title> </head> <body> <h1> 首页 </h1> <p th:text = "${msg}" ></p> <a th:href = "@{/user/add}" rel = "external nofollow" rel = "external nofollow" rel = "external nofollow" > add </a> | <a th:href = "@{/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://HdhCmsTestw3.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 ; @Controller public 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 ; @Configuration public class ShiroConfig { //4. ShiroFilterFactoryBean @Bean public ShiroFilterFactoryBean getshiroFilterFactoryBean ( @Qualifier ( "SecurityManager" ) DefaultWebSecurityManager defaultWebSecurityManager ){ ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean (); //5. 设置安全管理器 factoryBean . setSecurityManager ( defaultWebSecurityManager ); /* shiro内置过滤器 anon 无需授权、登录就可以访问,所有人可访。 authc 需要登录授权才能访问。 authcBasic Basic HTTP身份验证拦截器 logout 退出拦截器。退出成功后,会 redirect到设置的/URI noSessionCreation 不创建会话连接器 perms 授权拦截器,拥有对某个资源的权限才可访问 port 端口拦截器 rest rest风格拦截器 roles 角色拦截器,拥有某个角色的权限才可访问 ssl ssl拦截器。通过https协议才能通过 user 用户拦截器,需要有remember me功能方可使用 */ Map < String , String > filterMap = new LinkedHashMap <>(); //对/user/*下的文件只有拥有authc权限的才能访问 filterMap . put ( "/user/*" , "authc" ); //将Map存放到ShiroFilterFactoryBean中 factoryBean . setFilterChainDefinitionMap ( filterMap ); //需进行权限认证时跳转到toLogin factoryBean . setLoginUrl ( "/toLogin" ); //权限认证失败时跳转到unauthorized factoryBean . setUnauthorizedUrl ( "/unauthorized" ); return factoryBean ; } //2.创建DefaultWebSecurityManager @Bean ( name = "SecurityManager" ) public DefaultWebSecurityManager getDefaultWebSecurityManager ( @Qualifier ( "userRealm" ) UserRealm userRealm ){ DefaultWebSecurityManager SecurityManager = new DefaultWebSecurityManager (); //3.关联Realm SecurityManager . 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配置一下和Druid
Druid
mybatis
mybatis : type - aliases - package : com . example . pojo mapper - locations : classpath : mapper /*.xml
连接数据库
编写实体类
编写mapper
package com . example . mapper ; import com . example . pojo . User ; import org . apache . ibatis . annotations . Mapper ; import org . springframework . stereotype . Repository ; @Repository @Mapper public interface UserMapper { public User getUserByName ( String name ); }编写mapper.xml
<? xml version = "1.0" encoding = "UTF8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace = "com.example.mapper.UserMapper" > <select id = "getUserByName" 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 ; @Service public 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写跳转未授权页面
运行效果:
从数据库中接受用户的权限,进行判断
在数据库中添加一个属性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测试数据/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://HdhCmsTestthymeleaf.org" xmlns:shiro = "http://HdhCmsTestthymeleaf.org/thymeleaf-extras-shiro" > <!-- 三个命名空间 xmlns:th="http://HdhCmsTestthymeleaf.org" xmlns:sec="http://HdhCmsTestthymeleaf.org/extras/spring-security" xmlns:shiro="http://HdhCmsTestthymeleaf.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 = "@{/toLogin}" rel = "external nofollow" > 登录 </a> </div> <div shiro:hasPermission = "user:add" > <a th:href = "@{/user/add}" rel = "external nofollow" rel = "external nofollow" rel = "external nofollow" > add </a> </div> <div shiro:hasPermission = "user:update" > <a th:href = "@{/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的资料请关注其它相关文章!
原文链接:https://juejin.cn/post/6949793422483914789
查看更多关于Java安全框架——Shiro的使用详解(附springboot整合Shiro的demo)的详细内容...