Shiro

Shiro

依赖

    <!--shiro权限管理-->
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-spring</artifactId>
        <version>1.4.1</version>
    </dependency>
    <!--整合thymeleaf -->
    <dependency>
        <groupId>com.github.theborakompanioni</groupId>
        <artifactId>thymeleaf-extras-shiro</artifactId>
        <version>2.0.0</version>
    </dependency>

Shiro核心的三个对象

  1. Subject 用户 //ShiroFilterFactoryBean
  2. SecurityManager 管理所有用户 //DefaultWebSecurityManager
  3. Realm 连接数据 //创建 realm 对象

加盐加密方法

/**
* 加盐加密
* @param srcPwd    原始密码
* @param saltValue 盐值
*/
public static String salt(Object srcPwd, String saltValue){
return new SimpleHash("MD5", srcPwd, saltValue, 1024).toString();
}

UserRealm类 进行授权和认证

package com.kai.config;

import com.kai.pojo.model.User;
import com.kai.service.UserService;
import com.kai.utils.SideUtils;
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.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

//自定义的Realm
public class UserRealm extends AuthorizingRealm {

    @Autowired
    UserService userService;

    //授权方法
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //info.addStringPermission("user:add");

        //获取当前用户
        Subject subject = SecurityUtils.getSubject();

        //这里取出的是认证方法中存的值【user】return new SimpleAuthenticationInfo(user,user.getPwd(),"");
        //拿到user对象
        User currentUser = (User) subject.getPrincipal();
		//给user添加授权(授权类型保存在数据库中)
        info.addStringPermission(currentUser.getGroupName());

        //记得return!
        return info;
    }
    //认证方法
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

        //将方法传参得来的token强转为UsernamePasswordToken
        //Token可以获取到Controller中封装的用户登录数据
        UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;

        //用户名、密码  连接数据库取得
        //通过Token获取到Controller中封装的用户名,查询数据库中的用户
        User user = userService.queryUserByName(userToken.getUsername());
        if (user==null){
            return null;//return null会自动抛出UnknownAccountException异常
        }
		
		//加盐
        ByteSource salt = ByteSource.Util.bytes(//盐);
        String saltPassword = SideUtils.salt(userToken.getPassword(),user.getCreatedTime().toString());
		//比对加盐后密码是否与数据库中的密码相同
        if (!user.getPassword().equals(saltPassword)){
            throw new IncorrectCredentialsException("输入密码不正确!");
        }
        //密码认证由Shiro自动完成
        //可以进行MD5加密
        return new SimpleAuthenticationInfo(user,userToken.getPassword(),salt,getName());
    }
}

ShiroConfig类

package com.kai.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
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
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //设置安全管理器
        bean.setSecurityManager(defaultWebSecurityManager);

        //添加Shiro的内置过滤器
        /*
        anon:无需认证即可访问
        authc:必须认证后才可访问
        user:必须拥有 记住我 功能才可访问
        perms:拥有对某个资源的权限才可访问
        role:拥有某个角色的权限才可访问
         */
        //创建一个Map用于传值
        Map<String, String> filterMap = new LinkedHashMap<>();

        //设置/admin及其下页面需要认证后才可访问
        //通过通配符简化以上设置
        filterMap.put("/admin/*","authc");
        filterMap.put("/admin","authc");

        //配置退出登录的链接
        filterMap.put("/logout","logout");
		
        bean.setFilterChainDefinitionMap(filterMap);

        //设置登录页面的请求
        bean.setLoginUrl("/toLogin");

        //设置未授权用户跳转的请求
        bean.setUnauthorizedUrl("/unauthorized");
        return bean;
    }

    //二、DefaultWebSecurityManager
    //使用@Qualifier("userRealm")将下方定义的类交给Spring托管的realm类参数从IOC容器取出
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm")UserRealm userRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(userRealm);
        return securityManager;
    }

    //一、创建 realm 连接数据对象 ,需要自定义类
    @Bean(name = "userRealm")//将自定义的realm类交给Spring托管
    public UserRealm userRealm(){
        return new UserRealm();
    }
    //整合ShiroDialect:用来整合ThymeLeaf
    @Bean
    public ShiroDialect getShiroDialect(){
        return new ShiroDialect();
    }
}

controller

@PostMapping("/login")
public String Login(Model model,
                    String username,
                    String password){
    if (username.isEmpty()){
        model.addAttribute("msg",ErrorConstant.User.EMPTY_USERNAME);
        return "admin/login";
    }
    if (password.isEmpty()){
        model.addAttribute("msg",ErrorConstant.User.EMPTY_PASSWORD);
        return "admin/login";
    }

    //获取当前的用户
    Subject subject = SecurityUtils.getSubject();
    //封装用户的登录数据以便UserRealm类调用
    UsernamePasswordToken token = new UsernamePasswordToken(username, password);

    //执行登录的方法,如果没有异常就说明OK了
    try {
        subject.login(token);//执行登陆操作
        return "redirect:admin/index";//登录成功则跳转首页
    } catch (UnknownAccountException uae) {//捕获用户不存在异常
        model.addAttribute("msg",ErrorConstant.User.WRONG_USERNAME);
        return "admin/login";
    } catch (IncorrectCredentialsException ice) {//密码不存在异常
        model.addAttribute("msg",ErrorConstant.User.WRONG_PASSWORD);
        return "admin/login";
    } catch (LockedAccountException lae) {//用户被锁定异常
        model.addAttribute("msg",ErrorConstant.User.USER_LOCKED);
        return "admin/login";
    }
}