java-使用shiro对不同角色登录分配对应的权限

一、引入依赖(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。

--------------明天更,今天先到这里,有不懂的或者建议可以提出来!!看到就回!!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值