一、引入依赖(springboot)
<!--shiro 依赖-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.1</version>
</dependency>
<!--shiro 和 thymeleaf 整合-->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
二、Shiro
shiro可以用来登录认证(Authentication),加密(Cryptography),授权(Authorization),会话管理,可以作为安全框架来使用。我们先来学习一般加密方法。
三、一般加密方法
注意这里不是shiro加密,是使用Md5Hash加密,详细代码如下
@Test//加密
public void test01(){
//普通加密 123作为密码
Md5Hash md5Hash = new Md5Hash("123");
System.out.println("md5Hash = " + md5Hash);
//普通加密觉得还不安全,加入 盐
String salt="0d97c0c016d4759268b75a25d6eb4eb5";
Md5Hash md5Hash1 = new Md5Hash("123", salt);
System.out.println("md5Hash1 = " + md5Hash1);//安全的很
//若觉得还不安全,打散1024次,再来,此时非常安全了
Md5Hash md5Hash2 = new Md5Hash("123", salt, 1024);
System.out.println("md5Hash2 = " + md5Hash2);
}
四、shiro的组成
shiro有三个主体,分别是realm、securityManager和subject,由它们共同完成认证加密授权
realm:
相当于数据库里的数据,当shiro需要验证用户身份或获取用户权限时,会从realm中查找相关信息;shiro内置了多种realm实现,用于连接不同的安全数据源,如LDAP、关系数据库等; 可以自定义realm。
securityManager:
是shiro的核心组件。负责管理所有用户的安全操作;
当应用代码与Subject交互时,实际上是与securityManager内部的特定subject进行交互;
securityManager的缺省实现是pojo,可以通过Java代码、springxml等进行配置。
subject:
指当前操作的用户;应用代码直接交互的对象是Subject;
Subject包含了Principals(身份标识,如用户名)和Credentials(凭证,如密码)两个信息。
每个Subject对象都必须与一个SecurityManager进行绑定。
通过Subject,应用代码可以执行安全操作,如登录、访问控制等。
五、编写shiro的登录认证+加密+授权代码
1)shiro的配置文件
需要先把ream和securityManager提前创建,在初始化realm里定义使用md5加密;配置全局的拦截器;
package com.xiexin.shiro;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;
// 配置shiro , 需要 项目 中 shiro的配置
// 即 3个 对象[ realm , securityManager , subject[不要在这个类中创建] ] 提前创建
// 要想 对象 提前 创建!。。 需要用一个注解! @Configuration + @Bean
@Configuration
public class ShiroConfig {
// realm 的创建
@Bean // 相当于 类上 的 @Controller , @Servcie 。。四大注解。。。
public Realm realm(){
MybatisRealm realm = new MybatisRealm();
-----shiro的加密!!!!!!
HashedCredentialsMatcher matcher=new HashedCredentialsMatcher();
matcher.setHashAlgorithmName("md5");
matcher.setHashIterations(1024);
realm.setCredentialsMatcher(matcher);//加盐加密
return realm;
}
// securityManager 的创建----一个realm有一个securityManager
@Bean
public DefaultWebSecurityManager securityManager (Realm realm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(realm);
return securityManager;
}
// 最外层的 shiro 接管
@Bean
public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
shiroFilterFactoryBean.setLoginUrl("/index"); // 指定登录页
// 设置 那些页面 拦截,那些页面不拦截【登录, 登录的功能不拦截】
Map filterChainDefinitionMap = new LinkedHashMap();// 有顺序!
// 不拦截的界面
filterChainDefinitionMap.put("/index", "anon"); // anon 代表 不拦截
filterChainDefinitionMap.put("/", "anon");
filterChainDefinitionMap.put("/js/**", "anon");
filterChainDefinitionMap.put("/admin/shiroLogin", "anon");
// 需要拦截
filterChainDefinitionMap.put("/**", "authc"); // authc 代表 不登录不能进入
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
}
2)mybatisRealm,realm配置文件
package com.xiexin.shiro;
import com.xiexin.entity.po.Admin;
import com.xiexin.entity.query.AdminQuery;
import com.xiexin.service.AdminService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import javax.annotation.Resource;
import java.util.List;
public class MybatisRealm extends AuthorizingRealm {
@Resource
private AdminService adminService;
//授权 3 种触发 : 1.硬编码 ; 注解(前后端分离常用) ; 页面标签(前后端分离无此模式)
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("我是授权,我被触发了");
System.out.println("principalCollection = " + principalCollection);
return null;
}
// Authenticat 登录, 认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
// 拿 用户的信息。。 根据 subject 提供的账户名和密码进行查找。。。
System.out.println("authenticationToken = " + authenticationToken);
System.out.println("账号 = " + authenticationToken.getPrincipal());
System.out.println("密码 = " + authenticationToken.getCredentials());
//上面是前端传来的用户名和密码
//接下来要和DB中的数据作比较
//1.根据账户名查询
AdminQuery adminQuery = new AdminQuery();
adminQuery.setAdminAccount((String)authenticationToken.getPrincipal());
List<Admin> listByParam = adminService.findListByParam(adminQuery);
if(listByParam.size() !=1){
//账户名错误
return null;
}else{
SimpleAuthenticationInfo info= // 账户名
new SimpleAuthenticationInfo(authenticationToken.getPrincipal(),
// 数据库中的密码
listByParam.get(0).getAdminPwd(),// 加盐 本类的名
ByteSource.Util.bytes(listByParam.get(0).getSalt()),this.getName());
System.out.println("info = " + info);
return info;
}
// 返回null 代表 永远登录不了。
}
}
六、controller层使用shiro
@Resource
private AdminService adminService;
@GetMapping("/adminInfo")
public ResponseVO adminInfo(){
//触发硬编码
System.out.println("测试 硬编码 触发授权");
//硬编码 触发
Subject subject = SecurityUtils.getSubject();
boolean teacher = subject.hasRole("teacher");//判断是否有指定角色
System.out.println("teacher = " + teacher);
//subject.isPermitted("admin:add");//判断是否有指定权限
//---上面要从数据库中获取
ResponseVO responseVO = new ResponseVO();
responseVO.setCode(200);
responseVO.setInfo("测试成功");
return responseVO;
}
@PostMapping("/shiroLogin") // admin/shiroLogin
public ResponseVO shiroLogin(@RequestBody AdminQuery admin){
ResponseVO vo= new ResponseVO();
// 用一个 subject 的对象 来 用的
Subject subject = SecurityUtils.getSubject();
// 需要要给 token
UsernamePasswordToken token = new UsernamePasswordToken(admin.getAdminAccount(), admin.getAdminPwd());
try {
subject.login(token);//登陆验证
vo.setCode(200);
vo.setInfo("登录成功");
return vo ;
} catch (AuthenticationException e) {
throw new BusinessException(ResponseCodeEnum.CODE_501 );
}
}
执行controller中shiroLogin方法的subject.login(token)时,会触发MybatisRealm 中认证方法doGetAuthenticationInfo,接收的参数就是传来的token。
--------------明天更,今天先到这里,有不懂的或者建议可以提出来!!看到就回!!