美文网首页
Shiro安全框架学习记录

Shiro安全框架学习记录

作者: weisen | 来源:发表于2019-09-26 15:08 被阅读0次

    参考来源

    Shiro安全框架

    一、Shiro认识和介绍

    1、什么是Shiro
    Apache的强大灵活的开源安全框架
    认证、授权、企业会话管理、安全加密

    2、Shiro与Spring Security比较

    Shiro Spring Security
    简单、灵活 复杂、笨重
    可脱离Spring 不可脱离Spring
    粒度较粗 粒度更细

    3、Shiro整体架构

    [图片上传失败...(image-d9c4de-1568169456216)]

    二、Shiro认证授权过程

    1、Shiro认证过程

    graph LR
    A(创建SecurityManager) -->B(主体提交认证)
    B --> C(SecurityManager认证)
    C --> D(Authenticator认证)
    D --> E(Realm认证)
    

    代码:

     SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm();
        @Before
        public void addUser(){
            simpleAccountRealm.addAccount("admin","admin123","admin","user");
        }
    
        @Test
        public void testAuthentication(){
            //创建SecurityManager
            DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
            defaultSecurityManager.setRealm(simpleAccountRealm);
            //获取主体
            SecurityUtils.setSecurityManager(defaultSecurityManager);
            Subject subject = SecurityUtils.getSubject();
            //主体提交认证
            UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("admin", "admin123");
            subject.login(usernamePasswordToken);
            System.out.println("subject.isAuthenticated: "+subject.isAuthenticated());
            subject.logout();
            System.out.println("subject.isAuthenticated: "+subject.isAuthenticated());
        }
    

    2、Shiro授权过程

    graph LR
    A(创建SecurityManager) -->B(主体授权)
    B --> C(SecurityManager授权)
    C --> D(Authorizer授权)
    D --> E(Realm获取角色权限数据)
    

    代码:

        subject.login(usernamePasswordToken);
        System.out.println("subject.isAuthenticated: "+subject.isAuthenticated());
        subject.checkRole("admin");
        subject.checkRoles("admin","user");
    

    三、Shiro的Realm

    1、Shiro的iniRealm使用

    在Test Resources中添加文件user.ini,在里面添加用户信息

    [users]
    Admin=admin123,admin
    Tom=tom123,system
    [roles]
    admin=user:delete
    system=user:update
    

    代码

     @Test
        public void testAuthentication(){
            IniRealm iniRealm = new IniRealm("classpath:user.ini");
            //创建SecurityManager
            DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
            defaultSecurityManager.setRealm(iniRealm);
            //获取主体
            SecurityUtils.setSecurityManager(defaultSecurityManager);
            Subject subject = SecurityUtils.getSubject();
    
            //主体提交认证
            UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("Tom", "tom123");
            subject.login(usernamePasswordToken);
            System.out.println("subject.isAuthenticated: "+subject.isAuthenticated());
            subject.checkRole("system");
            subject.checkPermission("user:update");
    
    
        }
    

    2、Shiro的JdbcRealm使用

    代码:

     DruidDataSource datasource = new DruidDataSource();
        {
            datasource.setUrl("jdbc:mysql://192.168.243.20:9097/user_role");
            datasource.setUsername("root");
            datasource.setPassword("b#12345678");
        }
     @Test
        public void testAuthentication(){
            JdbcRealm jdbcRealm = new JdbcRealm();
            jdbcRealm.setDataSource(datasource);
            //创建SecurityManager
            DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
            defaultSecurityManager.setRealm(jdbcRealm);
    
            //获取主体
          ...
        }    
    

    因为JdbcRealm中会默认查询

    DEFAULT_AUTHENTICATION_QUERY = "select password from users where username = ?";
    

    所以在对应的库中添加users表,并带有相应字段和数据,则可查询成功

    需要使用自定义的查询表时,可使用自定义的查询sql语句

    String authSql = "select phone from aur_member where member_name = ?";
    jdbcRealm.setAuthenticationQuery(authSql);
    UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("tim1", "13751836453");
    

    3、Shiro自定义Realm

    继承AuthorizingRealm类,doGetAuthorizationInfo是授权,doGetAuthenticationInfo是认证

    public class CustomRealm extends AuthorizingRealm {
        Map<String,String> userMap = new HashMap<>();
        {
            userMap.put("admin","admin123");
            super.setName("customRealm");
        }
    
    
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            String userName = (String) principalCollection.getPrimaryPrincipal();
            //从数据库或者缓存中获取角色数据
            Set<String> roles = getRolesByUserName(userName);
            Set<String> permissions = getPermissionByUserName(userName);
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
            simpleAuthorizationInfo.setRoles(roles);
            simpleAuthorizationInfo.setStringPermissions(permissions);
            return simpleAuthorizationInfo;
        }
    
        private Set<String> getPermissionByUserName(String userName) {
            Set<String> sets = new HashSet<>();
            sets.add("user:delete");
            sets.add("user:add");
            sets.add("user:select");
            return sets;
        }
    
        private Set<String> getRolesByUserName(String userName) {
            Set<String> sets = new HashSet<>();
            sets.add("admin");
            sets.add("system");
            return sets;
        }
    
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            //1、从主体传过来的认证信息中,获取用户名
            String userName = (String) authenticationToken.getPrincipal();
            //2、通过用户名到数据库中获取凭证
            String password = getPasswordByUserName(userName);
            if (password == null){
                return null;
            }
            SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo("admin",password,"customRealm");
            return authenticationInfo;
        }
    
        // 模拟数据库
        private String getPasswordByUserName(String userName) {
           return userMap.get(userName);
        }
    }
    

    创建单元测试类

    @Test
        public void testAuthentication(){
            CustomRealm customRealm = new CustomRealm();
            //创建SecurityManager
            DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
            defaultSecurityManager.setRealm(customRealm);
    
            //获取主体
            SecurityUtils.setSecurityManager(defaultSecurityManager);
            Subject subject = SecurityUtils.getSubject();
    
            //主体提交认证
            UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("admin", "admin123");
            subject.login(usernamePasswordToken);
            System.out.println("subject.isAuthenticated: "+subject.isAuthenticated());
            subject.checkRole("admin");
            subject.checkPermissions("user:delete","user:select");
        }
    

    四、Shiro加密

    1、HashedCredentialsMatcher

    在CustomRealmTest的testAuthentication方法中添加上

    HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
            //加密的算法
            matcher.setHashAlgorithmName("md5");
            //加密的次数
            matcher.setHashIterations(1);
            customRealm.setCredentialsMatcher(matcher);
    

    在数据库中保存的密码就需要MD5加密后的结果

    public static void main(String[] args) {
        Md5Hash md5Hash = new Md5Hash("admin123");
        System.out.println(md5Hash.toString());
    }
    

    2、自定义Realm中使用散列

    3、盐的使用

    使用盐后的MD5值,将该值保存到数据库的表密码中

    public static void main(String[] args) {
        Md5Hash md5Hash = new Md5Hash("admin123","admin");
        System.out.println(md5Hash.toString());
    }
    

    在CustomRealm的doGetAuthenticationInfo方法中添加上

    authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes("admin"));
    

    相关文章

      网友评论

          本文标题:Shiro安全框架学习记录

          本文链接:https://www.haomeiwen.com/subject/tjeiyctx.html