5.7 开发授权
1.realm的实现
public class CustomerRealm extends AuthorizingRealm { //认证方法 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { String primaryPrincipal = (String) principals.getPrimaryPrincipal(); System.out.println("primaryPrincipal = " + primaryPrincipal); SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); simpleAuthorizationInfo.addRole("admin"); simpleAuthorizationInfo.addStringPermission("user:update:*"); simpleAuthorizationInfo.addStringPermission("product:*:*"); return simpleAuthorizationInfo; } //授权方法 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String principal = (String) token.getPrincipal(); if("xiaochen".equals(principal)){ String password = "3c88b338102c1a343bcb88cd3878758e"; String salt = "Q4F%"; return new SimpleAuthenticationInfo(principal,password, ByteSource.Util.bytes(salt),this.getName()); } return null; } }
2.授权
public class TestAuthenticatorCusttomerRealm { public static void main(String[] args) { //创建securityManager DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager(); //IniRealm realm = new IniRealm("classpath:shiro.ini"); //设置为自定义realm获取认证数据 CustomerRealm customerRealm = new CustomerRealm(); //设置md5加密 HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher(); credentialsMatcher.setHashAlgorithmName("MD5"); credentialsMatcher.setHashIterations(1024);//设置散列次数 customerRealm.setCredentialsMatcher(credentialsMatcher); defaultSecurityManager.setRealm(customerRealm); //将安装工具类中设置默认安全管理器 SecurityUtils.setSecurityManager(defaultSecurityManager); //获取主体对象 Subject subject = SecurityUtils.getSubject(); //创建token令牌 UsernamePasswordToken token = new UsernamePasswordToken("xiaochen", "123"); try { subject.login(token);//用户登录 System.out.println("登录成功~~"); } catch (UnknownAccountException e) { e.printStackTrace(); System.out.println("用户名错误!!"); }catch (IncorrectCredentialsException e){ e.printStackTrace(); System.out.println("密码错误!!!"); } //认证通过 if(subject.isAuthenticated()){ //基于角色权限管理 boolean admin = subject.hasRole("admin"); System.out.println(admin); boolean permitted = subject.isPermitted("product:create:001"); System.out.println(permitted); } } }
6.整合SpringBoot项目实战
6.0 整合思路
6.1 创建springboot项目
6.2 引入shiro依赖
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-starter</artifactId> <version>1.5.3</version> </dependency>
6.3 配置shiro环境
0.创建配置类
1.配置shiroFilterFactoryBean
@Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean(SecurityManager securityManager){ //创建shiro的filter ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); //注入安全管理器 shiroFilterFactoryBean.setSecurityManager(securityManager); return shiroFilterFactoryBean; }
2.配置WebSecurityManager
@Bean public DefaultWebSecurityManager getSecurityManager(Realm realm){ DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager(); defaultWebSecurityManager.setRealm(realm); return defaultWebSecurityManager; }
3.创建自定义realm
public class CustomerRealm extends AuthorizingRealm { //处理授权 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { return null; } //处理认证 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { return null; } }
4.配置自定义realm
//创建自定义realm @Bean public Realm getRealm(){ return new CustomerRealm(); }
5.编写控制器跳转至index.html
@Controller public class IndexController { @RequestMapping("index") public String index(){ System.out.println("跳转至主页"); return "index"; } }
6.启动springboot应用访问index
注意:
默认在配置好shiro环境后默认环境中没有对项目中任何资源进行权限控制,所有现在项目中所有资源都可以通过路径访问
7.加入权限控制
修改ShiroFilterFactoryBean配置
//注入安全管理器 shiroFilterFactoryBean.setSecurityManager(securityManager); Map<String,String> map = new LinkedHashMap<>(); map.put("/**","authc"); //配置认证和授权规则 shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
/** 代表拦截项目中一切资源 authc 代表shiro中的一个filter的别名,详细内容看文档的shirofilter列表
8.重启项目访问查看
6.4 常见过滤器
注意: shiro提供和多个默认的过滤器,我们可以用这些过滤器来配置控制指定url的权限:
配置缩写 | 对应的过滤器 | 功能 |
anon | AnonymousFilter | 指定url可以匿名访问 |
authc | FormAuthenticationFilter | 指定url需要form表单登录,默认会从请求中获取username、password,rememberMe等参数并尝试登录,如果登录不了就会跳转到loginUrl配置的路径。我们也可以用这个过滤器做默认的登录逻辑,但是一般都是我们自己在控制器写登录逻辑的,自己写的话出错返回的信息都可以定制嘛。 |
authcBasic | BasicHttpAuthenticationFilter | 指定url需要basic登录 |
logout | LogoutFilter | 登出过滤器,配置指定url就可以实现退出功能,非常方便 |
noSessionCreation | NoSessionCreationFilter | 禁止创建会话 |
perms | PermissionsAuthorizationFilter | 需要指定权限才能访问 |
port | PortFilter | 需要指定端口才能访问 |
rest | HttpMethodPermissionFilter | 将http请求方法转化成相应的动词来构造一个权限字符串,这个感觉意义不大,有兴趣自己看源码的注释 |
roles | RolesAuthorizationFilter | 需要指定角色才能访问 |
ssl | SslFilter | 需要https请求才能访问 |
user | UserFilter | 需要已登录或“记住我”的用户才能访问 |
6.5 认证实现
1. 在login.jsp中开发认证界面
<form action="${pageContext.request.contextPath}/user/login" method="post"> 用户名:<input type="text" name="username" > <br/> 密码 : <input type="text" name="password"> <br> <input type="submit" value="登录"> </form>
2. 开发controller
@Controller @RequestMapping("user") public class UserController { /** * 用来处理身份认证 * @param username * @param password * @return */ @RequestMapping("login") public String login(String username,String password){ //获取主体对象 Subject subject = SecurityUtils.getSubject(); try { subject.login(new UsernamePasswordToken(username,password)); return "redirect:/index.jsp"; } catch (UnknownAccountException e) { e.printStackTrace(); System.out.println("用户名错误!"); }catch (IncorrectCredentialsException e){ e.printStackTrace(); System.out.println("密码错误!"); } return "redirect:/login.jsp"; } }
在认证过程中使用subject.login进行认证
3.开发realm中返回静态数据(未连接数据库)
@Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println("=========================="); String principal = (String) token.getPrincipal(); if("xiaochen".equals(principal)){ return new SimpleAuthenticationInfo(principal,"123",this.getName()); } return null; } }
4.启动项目以realm中定义静态数据进行认证
![\[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WpDESR27-1667531467200)(Shiro 实战教程.assets/image-20200526082620621.png)\]](https://ucc.alicdn.com/images/user-upload-01/4dc8bc7fab1a49b180d1a2da4ca2da20.png)
认证功能没有md5和随机盐的认证就实现啦
6.6 退出认证
1.开发页面退出连接
2.开发controller
@Controller @RequestMapping("user") public class UserController { /** * 退出登录 * */ @RequestMapping("logout") public String logout(){ Subject subject = SecurityUtils.getSubject(); subject.logout();//退出用户 return "redirect:/login.jsp"; } }
3.修改退出连接访问退出路径
4.退出之后访问受限资源立即返回认证界面
6.7 MD5、Salt的认证实现
1.开发数据库注册
0.开发注册界面
<h1>用户注册</h1> <form action="${pageContext.request.contextPath}/user/register" method="post"> 用户名:<input type="text" name="username" > <br/> 密码 : <input type="text" name="password"> <br> <input type="submit" value="立即注册"> </form>
1.创建数据表结构
SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for t_user -- ---------------------------- DROP TABLE IF EXISTS `t_user`; CREATE TABLE `t_user` ( `id` int(6) NOT NULL AUTO_INCREMENT, `username` varchar(40) DEFAULT NULL, `password` varchar(40) DEFAULT NULL, `salt` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; SET FOREIGN_KEY_CHECKS = 1;
2.项目引入依赖
<!--mybatis相关依赖--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.2</version> </dependency> <!--mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency> <!--druid--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.19</version> </dependency>