2、认证,加密,授权,缓存

认证

1、Controller登录方法

@RequestMapping("/login.do")
public String login(User user,ModelMap map){
    //获得一个主体对象
    Subject subject = SecurityUtils.getSubject();
    //将请求得到的用户名和密码放入一个令牌中
    UsernamePasswordToken token = new UsernamePasswordToken(user.getUaccount(),user.getUpsw());
    //调用主体对象的认证方法login,对令牌进行认证
    try{
        //触发Realm中doGetAuthenticationInfo()
        subject.login(token);
        Session session = subject.getSession();
        User nwoLogin = (User)subject.getPrincipal();
        session.setAttribute("nowLogin", nwoLogin);
    }catch(UnknownAccountException accountException){
        map.put("ex", "账号不存在");
        return "tologin.do";
    }catch(IncorrectCredentialsException passwordExeption){
        map.put("ex", "密码校验错误");
        return "tologin.do";
    }
    return "redirect:toMain.do";
}

2、Realm类中,doGetAuthenticationInfo方法进行登录认证

//身份认证方法,需要在用户登录系统时触发
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
    //通过方法形参arg0,获取封装了用户账号密码的令牌
    UsernamePasswordToken token = (UsernamePasswordToken)arg0;
    //验证账号是否存在
    String uaccount = token.getUsername();
    User user = userService.selectByUaccount(uaccount);
    if(user == null){
        //如果用户名不存在,返回null
        //则shiro底层返回了一个异常(UnknownAccountException)
        return null;
    }
    //验证密码是否正确
    //第一个参数为,数据库查出的user对象,第二个参数为正确的密码,第三个参数为当前realm名
    //如果密码不正确,该构造器会抛出异常(IncorrectCredentialsException)
    return new SimpleAuthenticationInfo(user,user.getUpsw(),getName());
}

加密

1、ShiroConfig类中,设置加密

//设置加密类型(身份匹配器),以及方式
@Bean
public HashedCredentialsMatcher credentialsMatcher() {
    HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
    // 说密码的加密方式为MD5 (不可逆的加密方式,只能加密,不能解密)
    credentialsMatcher.setHashAlgorithmName("MD5");
    // 针对MD5加密的信息,再加密1024次
    credentialsMatcher.setHashIterations(1024);
    return credentialsMatcher;
}
//配置shiro框架中,用来完成身份认证,授权的域对象
@Bean
public LoginAndAuthRealm loginAndAuthRealm() {
    LoginAndAuthRealm realm = new LoginAndAuthRealm();
    // 给Realm中配置身份对比规则
    realm.setCredentialsMatcher(credentialsMatcher());
    return realm;
}

2、修改Realm组件身份认证方法

//身份认证方法,需要在用户登录系统时触发
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
    //通过方法形参arg0,获取封装了用户账号密码的令牌
    UsernamePasswordToken token = (UsernamePasswordToken)arg0;
    //验证账号是否存在
    String uaccount = token.getUsername();
    User user = userService.selectByUaccount(uaccount);
    if(user == null){
        //如果用户名不存在,返回null
        //则shiro底层返回了一个异常(UnknownAccountException)
        return null;
    }
    //验证密码是否正确
    //获取当前用户名,创建盐值对象
    ByteSource byteSource = ByteSource.Util.bytes(user.getUaccount());
    //第一个参数为,数据库查出的user对象,第二个参数为正确的密码,第三个参数为盐值对象,第四个参数为当前Realm名称
    //如果密码不正确,该构造器会抛出异常(IncorrectCredentialsException)
    return new SimpleAuthenticationInfo(user,user.getUpsw(),byteSource,getName());
}

3、控制层注册方法中,对密码进行MD5加密

String pwd = new SimpleHash("MD5", 密码,盐值‘一般为用户名’, 加密次数‘1024’).toString();

public String regist(User user){
    User nowLogin = userMapper.slecteByUaccount(user.getUaccount());
    if(nowLogin != null){
        return "用户已存在!!!";
    }else{
        String upsw = new SimpleHash("MD5",user.getUpsw(), user.getUaccount(), 1024).toString();
        user.setUpsw(upsw);
        int i = userMapper.insert(user);
        UserRole userRole = new UserRole();
        userRole.setUid(user.getUid());
        userRole.setRid(4);
        int j = userRoleMapper.insert(userRole);
        if(i > 0 && j > 0){
            return "注册成功!!!";
        }else{
            return "注册失败!!!";
        }
    }
}

授权

ShiroFilter工作原理

说明: clipboard.png

Shiro中过滤器的类型及配置

说明: clipboard.png

1、重写底层Roles规则,用于多个角色可以授权一个路径的访问(或的关系)

public class RolesFilter extends RolesAuthorizationFilter{
    @Override
    public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)
        throws IOException {
        final Subject subject = getSubject(request, response);
        final String[] rolesArray = (String[]) mappedValue;
        if (rolesArray == null || rolesArray.length == 0) {
            return true;
        }
        for (String roleName : rolesArray) {
            if (subject.hasRole(roleName)) {
                return true;
            }
        }
        return false;
    }
}  

2、ShiroConfig类中,设置过滤器链以及过滤器

@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(){
    ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
    //注入自定义的Roles权限规则
    Map<String,Filter> rolesMap = new HashMap<>();
    rolesMap.put("roles", new RolesFilter());
    shiroFilterFactoryBean.setFilters(rolesMap);
    //注入安全管理器
    shiroFilterFactoryBean.setSecurityManager(getDefaultWebSecurityManager());
    //添加登陆页面、登陆成功、未授权路径
    shiroFilterFactoryBean.setLoginUrl("/toLogin.do");
    shiroFilterFactoryBean.setSuccessUrl("/toMain.do");
    shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized.do");
    //添加对各种页面的限制
    Map<String,String> map = new LinkedHashMap<>();
    //登录页面、登录方法、注册方法,不需要限制(匿名)
    map.put("/toLogin.do", "anon");
    map.put("/login.do", "anon");
    map.put("/regist.do","anon");
    //查看用户信息,超级管理员或管理员才可以访问
    map.put("/list.do", "roles[超级管理员,管理员]");
    //其他页面,需要认证后才可以进行访问
    map.put("/*", "authc");
    shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
    return shiroFilterFactoryBean;
}

3、Realm授权方法中,对当前登录角色进行授权

@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
    //授权信息对象
    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    //获取当前登录用户
    User user = (User)SecurityUtils.getSubject().getPrincipal();
    //获取当前登录用户的角色信息
    List<UserRole> userRoles = user.getUserRoles();
    List<String> roles = new ArrayList<>();
    for(UserRole ur : userRoles){
        roles.add(ur.getRole().getRname());
    }
    //将当前登录用户的角色名称(String)存入授权信息对象中
    info.addRoles(roles);
    return info;
}