Shiro


Shiro

认证丶授权丶会话管理和加密等功能. 
shiro不提供和维护用户/权限,而是通过realm让开发人员自己注入

一、认证

在shiro中,认证指的是识别和证明操作者是一个合法用户

添加依赖

		 <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.1</version>
        </dependency>

方法一:
在resource目录下新建文件配置认证信息’

[users]
admin=123456
czkt=111111

编写测试
	@Test
public void testShiro() {
    IniRealm realm = new IniRealm("classpath:shiro.ini");
    DefaultSecurityManager securityManager = new DefaultSecurityManager();
    securityManager.setRealm(realm);

    SecurityUtils.setSecurityManager(securityManager);
    Subject subject = SecurityUtils.getSubject();
    UsernamePasswordToken token = new UsernamePasswordToken("admin", "123456");

    subject.login(token);
    System.out.println("是否通过:" + subject.isAuthenticated());
}

2.springboot+shiro认证

UserRepository 添加findUserByUserName方法

public interface UserRepository extends JpaRepository<User,Integer>,JpaSpecificationExecutor<User> {

    public List<User> findUsersByUserNameAndUserPassword(String userName,String userPassword);


    public User findUserByUserName(String userName);
}

UserService 接口 新增getUserByUserName

public interface UserService {
    public User getUserByUserName(String userName);
}

UserServiceImpl实现方法

    public User getUserByUserName(String userName) {
        return userRepository.findUserByUserName(userName);
    }

二丶自定义Realm

在config包下创建自定义realm对象MyShiroRealm:
注意导包一点要正确,不然会发生bean注入错误

import com.aiweiyi.crm.pojo.User;
import com.aiweiyi.crm.service.UserService;
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 javax.annotation.Resource;

public class MyShiroRealm extends AuthorizingRealm {

    @Resource
    private UserService userService;


//权限控制方法
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        User user = (User)principalCollection.getPrimaryPrincipal();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        return info;
    }

//认证方法
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String userName = token.getUsername();
        User user = userService.getUserByUserName(userName);
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getUserPassword(),getName());
        return info;
    }
}

在config包下创建配置对象ShiroConfig:

import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ShiroConfig {

    @Bean
    public MyShiroRealm myShiroRealm(){
        MyShiroRealm shiroRealm = new MyShiroRealm();
        return shiroRealm;
    }

    @Bean
    public SecurityManager securityManager(){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myShiroRealm());
        return securityManager;
    }

    @Bean
    public ShiroFilterFactoryBean shiroFilterFactory(SecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactory = new ShiroFilterFactoryBean();
        shiroFilterFactory.setSecurityManager(securityManager);
        return shiroFilterFactory;
    }
}

重写login方法

 @RequestMapping("/dologin")
    public String dologin(String userName, String userPassword, HttpServletRequest request) {
//        User user = userService.login(userName, userPassword);
//        if (user != null) {
//            request.getSession().setAttribute("loginUser", user);
//            return "main";
//        } else {
//
//            return "login";
//        }
        try{
            UsernamePasswordToken token = new UsernamePasswordToken(userName,userPassword);
            Subject subject = SecurityUtils.getSubject();
            subject.login(token);

            User user = (User)subject.getPrincipal();
            request.getSession().setAttribute("loginUser", user);
            return "main";
        }catch (UnknownAccountException | IncorrectCredentialsException e){
            request.setAttribute("error", "1用户名或密码错误!");
            return "login";
        }
    }


 	@RequestMapping("/logout")
    public String logout(HttpSession session) {
        session.removeAttribute("loginUser");
        SecurityUtils.getSubject().logout();  //Shiro注销
        return "login";
    }

三丶授权

修改上面配置文件
shiro.ini

[users]
admin=123456,管理员
czkt=111111,经理


[roles]
管理员=user:*,role:*

经理=user:list,user:view

测试

	@Test
    public void testShiro() {
        IniRealm realm = new IniRealm("classpath:shiro.ini");
        DefaultSecurityManager securityManager = new DefaultSecurityManager();
        securityManager.setRealm(realm);

        SecurityUtils.setSecurityManager(securityManager);
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("admin", "123456");


        subject.login(token);
        System.out.println("是否通过:" + subject.isAuthenticated());
        System.out.println("是否为管理员角色:"+subject.hasRole("管理员"));
        System.out.println("拥有权限:"+subject.isPermitted("user:view"));
        subject.checkPermission("user:view");

    }

授权支持四种方式
1.代码级别权限控制
2.页面标签权限控制
3.方法注解权限控制
4.url拦截权限控制

静态授权

修改自定义realm授权

public class MyShiroRealm extends AuthorizingRealm{

    @Resource
    private IUserService userService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection 	principalCollection) {
        System.out.println("调用MyShiroRealm.doGetAuthorizationInfo获取权限信息");
        User user=(User)principalCollection.getPrimaryPrincipal();
        SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
        //静态授权
        info.addRole(user.getRole().getRoleName());
        info.addStringPermission("用户列表");
        if (user.getRole().getRoleName().equals("管理员")){
            info.addStringPermission("用户添加");
            info.addStringPermission("用户编辑");
            info.addStringPermission("用户删除");
        }
        return info;
    }

配置shiro拦截

@Bean
    public ShiroFilterFactoryBean shiroFilterFactory(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactory = new ShiroFilterFactoryBean();
        shiroFilterFactory.setSecurityManager(securityManager);

        shiroFilterFactory.setLoginUrl("/login");
        shiroFilterFactory.setSuccessUrl("/main");
        shiroFilterFactory.setUnauthorizedUrl("/403");
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        filterChainDefinitionMap.put("/css/**", "anon");
        filterChainDefinitionMap.put("/fonts/**", "anon");
        filterChainDefinitionMap.put("/images/**", "anon");
        filterChainDefinitionMap.put("/js/**", "anon");
        filterChainDefinitionMap.put("/localcss/**", "anon");
        filterChainDefinitionMap.put("/localjs/**", "anon");

        filterChainDefinitionMap.put("/login", "anon");
        filterChainDefinitionMap.put("/dologin", "anon");
        filterChainDefinitionMap.put("/logout", "logout");


        filterChainDefinitionMap.put("/user/list", "perms[用户列表]");
        filterChainDefinitionMap.put("/user/add", "perms[用户添加]");
        filterChainDefinitionMap.put("/user/del", "perms[用户删除]");
        filterChainDefinitionMap.put("/user/updateUser", "perms[用户修改]");
        
        filterChainDefinitionMap.put("/**", "authc");

        shiroFilterFactory.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactory;
    }

动态授权

1 添加实体类

@Entity
@Table(name = "sys_right")
@JsonIgnoreProperties(value = {"hibernateLazyInitializer","handler"})
public class Right implements Serializable {
    @Id
    @Column(name = "right_code")
    private String rightCode;
    @Column(name = "right_parent_code")
    private String rightParentCode;
    @Column(name = "right_type")
    private String rightType;
    @Column(name = "right_test")
    private String rightTest;
    @Column(name = "right_url")
    private String rightUrl;
    @Column(name = "right_tip")
    private String rightTip;
	//多对多
	@ManyToMany(targetEntity = Role.class,mappedBy = "rights")
    @JsonIgnore
    private Set<Role> roles = new HashSet<Role>(0);
    
    //省略get/set方法,改造方法
}

2.修改Role实体类,添加与Right类的多对多关联``

@ManyToMany(targetEntity = Right.class, fetch = FetchType.EAGER)
    @JoinTable(name = "sys_role_right", joinColumns = {@JoinColumn(name = "rf_role_id")}, inverseJoinColumns = {@JoinColumn(name = "rf_right_code")})
    @OrderBy(value = "rightCode")
    private Set<Right> rights = new HashSet<Right>(0);

3.开发RightRepository

public interface RightRepository extends JpaRepository<Right,String> {
    public List<Right> findRightsByRolesOrderByRightCode(Role role);
}

4.在RoleService 接口中添加新的方法

public interface RoleService {
    public List<Role> findAllRoles();
    public List<Right> findAllRights();
    public List<Right> findRightsByRole(Role role);
}

5.调整controller

@RequestMapping("/dologin")
    public String dologin(String userName, String userPassword, HttpServletRequest request) {
//        User user = userService.login(userName, userPassword);
//        if (user != null) {
//            request.getSession().setAttribute("loginUser", user);
//            return "main";
//        } else {
//
//            return "login";
//        }
       try{
            UsernamePasswordToken token = new UsernamePasswordToken(userName,userPassword);
            Subject subject = SecurityUtils.getSubject();
            subject.login(token);
            User user = (User)subject.getPrincipal();
            Role role = user.getRole();
            List<Right> rights =roleService.findRightsByRole(role);
            role.getRights().addAll(rights);
            request.getSession().setAttribute("loginUser", user);
            return "redirect:/main";
        }catch (UnknownAccountException | IncorrectCredentialsException e){
            request.setAttribute("error", "用户名或密码错误!");
            return "login";
        }
    }

6.调整自定义realm

@Bean
    public ShiroFilterFactoryBean shiroFilterFactory(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactory = new ShiroFilterFactoryBean();
        shiroFilterFactory.setSecurityManager(securityManager);

        shiroFilterFactory.setLoginUrl("/login");
        shiroFilterFactory.setSuccessUrl("/main");
        shiroFilterFactory.setUnauthorizedUrl("/403");
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        filterChainDefinitionMap.put("/css/**", "anon");
        filterChainDefinitionMap.put("/fonts/**", "anon");
        filterChainDefinitionMap.put("/images/**", "anon");
        filterChainDefinitionMap.put("/js/**", "anon");
        filterChainDefinitionMap.put("/localcss/**", "anon");
        filterChainDefinitionMap.put("/localjs/**", "anon");
        filterChainDefinitionMap.put("/login", "anon");
        filterChainDefinitionMap.put("/dologin", "anon");
        filterChainDefinitionMap.put("/logout", "logout");
//        filterChainDefinitionMap.put("/user/list", "perms[用户列表]");
//        filterChainDefinitionMap.put("/user/add", "perms[用户添加]");
//        filterChainDefinitionMap.put("/user/del", "perms[用户删除]");
//        filterChainDefinitionMap.put("/user/updateUser", "perms[用户修改]");
        List<Right> rights = roleService.findAllRights();
        for (Right right : rights) {
            if (right.getRightUrl() != null && !right.getRightUrl().trim().equals("")) {
                filterChainDefinitionMap.put(right.getRightUrl(), "perms[" + right.getRightCode() + "]");
            }
        }
        filterChainDefinitionMap.put("/**", "authc");

        shiroFilterFactory.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactory;
    }

四丶会话管理和加密

1.会话相关API
Subject.getSession():获取会话
session.setAttribute(key,val):设置会话属性
session.getAttribute(key):获取会话属性
session.removeAttribute(key):删除会话属性

Shiro提供SessionDAO用于会话持久化,提供crud操作
在开发中,建议在Controller层使用原生的HttpSession对象,在Service层中使用Shiro提供的session对象.

2.缓存

设置缓存```java
package com.aiweiyi.crm.config.shiro;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.aiweiyi.crm.pojo.Right;
import com.aiweiyi.crm.service.RoleService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Configuration
public class ShiroConfig {

@Value("${spring.redis.host}")
private String host;

@Value("${spring.redis.port}")
private int port;

@Value("${spring.redis.timeout}")
private int timeout;

@Resource
private RoleService roleService;

@Bean
public DefaultAdvisorAutoProxyCreator autoProxyCreator() {
    DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
    autoProxyCreator.setProxyTargetClass(true);
    return autoProxyCreator;
}

@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
    AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
    authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
    return authorizationAttributeSourceAdvisor;
}

public RedisManager redisManager(){
    RedisManager redisManager = new RedisManager();
    redisManager.setHost(host);
    redisManager.setPort(port);
    redisManager.setTimeout(timeout);
    return redisManager;
}


public RedisCacheManager cacheManager(){
    RedisCacheManager cacheManager = new RedisCacheManager();
    cacheManager.setRedisManager(redisManager());

    cacheManager.setPrincipalIdFieldName("userName");

    cacheManager.setExpire(1800);
    return cacheManager;
}

private RedisSessionDAO redisSessionDAO(){
    RedisSessionDAO sessionDAO = new RedisSessionDAO();
    sessionDAO.setRedisManager(redisManager());
    return sessionDAO;
}


private DefaultWebSessionManager sessionManager(){
    DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
    sessionManager.setSessionDAO(redisSessionDAO());
    return sessionManager;
}

@Bean(name = "shiroDialect")
public ShiroDialect shiroDialect() {
    return new ShiroDialect();
}

@Bean
public MyShiroRealm myShiroRealm() {
    MyShiroRealm shiroRealm = new MyShiroRealm();
    shiroRealm.setCachingEnabled(true);
    shiroRealm.setAuthorizationCachingEnabled(true);
    shiroRealm.setAuthorizationCacheName("authorizationCache");

    shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());

    return shiroRealm;
}

@Bean
public SecurityManager securityManager() {
    DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    securityManager.setRealm(myShiroRealm());
    securityManager.setCacheManager(cacheManager());
    securityManager.setSessionManager(sessionManager());

// SecurityUtils.setSecurityManager(securityManager);
return securityManager;
}

@Bean
public ShiroFilterFactoryBean shiroFilterFactory(SecurityManager securityManager) {
    ShiroFilterFactoryBean shiroFilterFactory = new ShiroFilterFactoryBean();
    shiroFilterFactory.setSecurityManager(securityManager);

    shiroFilterFactory.setLoginUrl("/login");
    shiroFilterFactory.setSuccessUrl("/main");
    shiroFilterFactory.setUnauthorizedUrl("/403");
    Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
    filterChainDefinitionMap.put("/css/**", "anon");
    filterChainDefinitionMap.put("/fonts/**", "anon");
    filterChainDefinitionMap.put("/images/**", "anon");
    filterChainDefinitionMap.put("/js/**", "anon");
    filterChainDefinitionMap.put("/localcss/**", "anon");
    filterChainDefinitionMap.put("/localjs/**", "anon");

    filterChainDefinitionMap.put("/login", "anon");
    filterChainDefinitionMap.put("/dologin", "anon");
    filterChainDefinitionMap.put("/logout", "logout");

// filterChainDefinitionMap.put("/user/list", “perms[用户列表]”);
// filterChainDefinitionMap.put("/user/add", “perms[用户添加]”);
// filterChainDefinitionMap.put("/user/del", “perms[用户删除]”);
// filterChainDefinitionMap.put("/user/updateUser", “perms[用户修改]”);
List rights = roleService.findAllRights();
for (Right right : rights) {
if (right.getRightUrl() != null && !right.getRightUrl().trim().equals("")) {
filterChainDefinitionMap.put(right.getRightUrl(), “perms[” + right.getRightCode() + “]”);
}
}
filterChainDefinitionMap.put("/**", “authc”);

    shiroFilterFactory.setFilterChainDefinitionMap(filterChainDefinitionMap);
    return shiroFilterFactory;
}


@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher(){
    HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
    //md5加密
    hashedCredentialsMatcher.setHashAlgorithmName("md5");
    //设置加密次数
    hashedCredentialsMatcher.setHashIterations(2);

// hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
return hashedCredentialsMatcher;

}

}


# 加密

1.哈希与盐
特点:

原始密码经过哈希函数计算后得到一个哈希值
改变原始密码,哈希函数计算出的哈希值也会相应改变
同样的密码,哈希值也是相同的

```java
	@Test
    public void testMd5Hash(){
        Md5Hash md5=new Md5Hash("adming","czkt",3);
        System.out.println(md5.toString());
    }
package com.aiweiyi.crm.config.shiro;

import com.aiweiyi.crm.pojo.Right;
import com.aiweiyi.crm.pojo.Role;
import com.aiweiyi.crm.pojo.User;
import com.aiweiyi.crm.service.UserService;
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.util.ByteSource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;

import javax.annotation.Resource;
import java.util.Set;
import java.util.concurrent.TimeUnit;

public class MyShiroRealm extends AuthorizingRealm {


    @Resource
    private UserService userService;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    private String SHIRO_LOGIN_COUNT = "shiro_login_count";  //登录次数

    private String SHIRO_IS_LOCK = "shiro_is_lock";  //登录次数


    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        User user = (User) principalCollection.getPrimaryPrincipal();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

        Role role = user.getRole();
        if (role != null) {
            info.addRole(user.getRole().getRoleName());
            Set<Right> rights = role.getRights();
            if (rights != null && rights.size() > 0) {
                for (Right right : rights) {
                    info.addStringPermission(right.getRightCode());
                }
            }
        }

        return info;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String userName = token.getUsername();
        ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();
        opsForValue.increment(SHIRO_LOGIN_COUNT + userName, 1);
        if (Integer.parseInt(opsForValue.get(SHIRO_LOGIN_COUNT + userName)) > 2) {
            opsForValue.set(SHIRO_IS_LOCK + userName, "LOCK");
            stringRedisTemplate.expire(SHIRO_IS_LOCK + userName, 1, TimeUnit.HOURS);
            stringRedisTemplate.delete(SHIRO_LOGIN_COUNT + userName);
        }
        if ("LOCK".equals(opsForValue.get(SHIRO_IS_LOCK + userName))) {
            throw new DisabledAccountException();
        }

        User user = userService.getUserByUserName(userName);
        if (user == null) {
            throw new UnknownAccountException();
        }
        if (user.getUserFlag() == null || user.getUserFlag().intValue() == 0) {
            throw new LockedAccountException();
        }
//        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getUserPassword(), getName());

        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getUserPassword(), ByteSource.Util.bytes("czkt"), getName());
        return info;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值