(5).授权功能的实现
去到ShiroConfig.java中,添加代码,注意要添加在(顺序)
filterMap.put("/add","perms[user:add]"); filterMap.put("/add.html","perms[user:add]");
之后我们执行I一下发现登陆后add标签也无权访问
显示401的意思就是未授权
当然正常的是要访问无权限页面的(授权要写在认证的前面)
package com.jsxs.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 { // ShiroFilterFactoryBean ----》 Subject @Bean(name = "shiroFilterFactoryBean") public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){ // 通过注解指定是 public DefaultWebSecurityManager getDefaultWebSecurityManager 这个Bean ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager); //设置安全管理器 /** * anno :无需认证就可以访问 * authc : 必须认证了才能访问 * user :必须拥有 记住我 功能才有用 * perms : 拥有对某个资源的权限才能访问 * role : 拥有某个角色权限次啊能使用 */ // 拦截 // 认证才能访问 Map<String, String> filterMap = new LinkedHashMap<>();// filterMap.put("/add","perms[user:add]"); filterMap.put("/add.html","perms[user:add]"); filterMap.put("/update","authc"); filterMap.put("/update.html","authc"); // 授权才能访问 shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap); //这个一定要添加 //假如说没有认证/授权我们就会走这个路径 shiroFilterFactoryBean.setLoginUrl("/toLogin"); //假如说没有权限/认证我们就会走这个路径 //假如说此用户没有授权我们就会走如下的页面 shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized"); return shiroFilterFactoryBean; } //DefaultWebSecurityManger ----》 SecurityManger ---->02 @Bean public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){ // 通过注解指定是 public UserRealm userRealm() 这个Bean DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager(); defaultWebSecurityManager.setRealm(userRealm); //进行关联 Realm return defaultWebSecurityManager; } //创建 Realm 对象 ----》 Realm 需要自定义----> 01 @Bean(name = "userRealm") public UserRealm userRealm(){ return new UserRealm(); } }
接下来我们去UserRealm中给添加权限,注意不要导错类SimpleAuthorizationInfo
// 授权 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { System.out.println("执行了=》授权的方法"); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.addStringPermission("user:add"); //给用户添加这个权限 return info; }
package com.jsxs.config; import com.jsxs.pojo.User; import com.jsxs.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 javax.annotation.Resource; public class UserRealm extends AuthorizingRealm { // 授权 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { System.out.println("执行了=》授权的方法"); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.addStringPermission("user:add"); //给用户添加这个权限 return info; } //我们需要添加业务层的支持 @Resource UserService userService; // 认证 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println("执行了=》认证的方法"); // 链接虚拟的数据库 // String name = "admin"; // String password = "123456"; // 链接真实的数据库 UsernamePasswordToken userToken = (UsernamePasswordToken) token; User user = userService.queryByName(userToken.getUsername()); //获取前端的名字,通过前端的截取的用户名进行查询 if (user==null) { // 假如说查询的user为空,那么就返回null return null; // 抛出异常 UnknownAccount } // 密码认证 ----》Shiro帮我们做 return new SimpleAuthenticationInfo("",user.getPwd(),""); } }
诶,接下来所有用户就都有这个权限
了
但是不想让所有用户都有某个权限要怎么实现呢?
首先先去数据表中添加一个权限字段
并且要记得修改pojo实体类
package com.jsxs.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor public class User { private int id; private String name; private String pwd; private String perms; }
ok数据层完毕,接下来要思考,我们想要获取到用户的权限,但是获取用户是在刚刚认证中通过userservice获取的,
在认证里面查到的东西我们怎么放到授权中去呢?
想到了两个:①session ②用户当前对象的属性来取get方法或(点属性)
我们在认证中,最后new了一个SimpleAuthenticationInfo的当前认证对象,之前里面要传递三个参数分别为:
(资源,密码,realmName)
我们把获取到的user传入到资源中去。
return new SimpleAuthenticationInfo(user,user.getPwd(),"");
这样一来,user这个资源就传递到了当前用户subject整体资源中,通过当前subject获取资源来获取到这个user
所以在授权的功能中要先获取subject当前用户
Subject subject = SecurityUtils.getSubject();
然后通过subject获取到资源
User currentUser = (User) subject.getPrincipal();
再给当前用户添加user中对应的权限名,注意方法名是addStringPermission权限
info.addStringPermission(currentUser.getPerms());
最后返回当前权限info
package com.jsxs.config; import com.jsxs.pojo.User; import com.jsxs.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 javax.annotation.Resource; public class UserRealm extends AuthorizingRealm { // 授权 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { System.out.println("执行了=》授权的方法"); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); //info.addStringPermission("user:add"); //给所有用户添加这个权限 //拿到当前登入的这个对象 Subject subject = SecurityUtils.getSubject(); // 获取共享的数据--->拿到User对象 User currentUser = (User) subject.getPrincipal(); // 通过查询当前的数据库信息,设定当前用户的权限 info.addStringPermission(currentUser.getPerms()); return info; } //我们需要添加业务层的支持 @Resource UserService userService; // 认证 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println("执行了=》认证的方法"); // 链接虚拟的数据库 // String name = "admin"; // String password = "123456"; // 链接真实的数据库 UsernamePasswordToken userToken = (UsernamePasswordToken) token; User user = userService.queryByName(userToken.getUsername()); //获取前端的名字,通过前端的截取的用户名进行查询 if (user==null) { // 假如说查询的user为空,那么就返回null return null; // 抛出异常 UnknownAccount } // 密码认证 ----》Shiro帮我们做 return new SimpleAuthenticationInfo(user,user.getPwd(),""); //------->这里我们为第一个参数赋值,目的就是我们可以共享这个资源 } }
退出功能就和之前security的logout一样,设置一下退出的路径就可
好现在基本需求都完了,但是想和之前security一样实现没有权限的就不要显示,就需要和thymeleaf结合
(6).Shiro和thymeleaf整合
首先要导入shrio和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>
ok接下来就要去前端页面编写标签了,之前在security中用到的是sec,这里用的shiro,当然也要导入命名空间
下面是spring-security的命名空间
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5"
shiro的:
xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro"
或则
推荐
xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"
前端代码:
假如说存在权限add我们就显示,不存在的话就不显示
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro" > <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>首页</h1> <p> <a th:href="@{/toLogin}">登入</a> </p> <p th:text="${msg}"></p> <hr> <div shiro:hasPermission="user:add"> <a th:href="@{/add}">add</a> </div> <div shiro:hasPermission="user:update"> <a th:href="@{/update}">update</a> </div> </body> </html>
登录按钮无权限时显示:
<div shiro:notAuthenticated> <a th:href="@{/toLogin}">登录</a> </div>