shiro 通过jdbc连接数据库

本文介绍shiro通过jdbc连接数据库,连接池采用阿里巴巴的druid的连接池

参考文档:https://www.w3cschool.cn/shiro/xgj31if4.html

     https://www.w3cschool.cn/shiro/h5it1if8.html

pom.xml的配置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <artifactId>shiro-example-chapter2</artifactId>
        <groupId>com.github.zhangkaitao</groupId>
        <version>SNAPSHOT</version>
    <modelVersion>4.0.0</modelVersion>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.16</version>
        </dependency>

        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.25</version>
            <scope>test</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.3</version>
        </dependency>


        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.9</version>
            <scope>test</scope>
        </dependency>


        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.2.2</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.25</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.8</version>
        </dependency>

    </dependencies>


</project>

shiro.ini 文件的配置

[main]
dataSource=com.alibaba.druid.pool.DruidDataSource
dataSource.driverClassName=com.mysql.jdbc.Driver
dataSource.url=jdbc:mysql://localhost:3306/shiro
dataSource.username=root
dataSource.password=123456
jdbcRealm.dataSource=$dataSource


jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm

securityManager.realms=$jdbcRealm
jdbcRealm  shiro框架已经集成的安全域,安全域的作用是将资源(数据库,缓存,磁盘文件等)中用户身份的集合和需要匹配的集合进行验证,决定登录用户的身份是否能验证成功的功能。如果要自定义安全域,只要继承
AuthorizingRealm 这个接口。实现doGetAuthenticationInfo() 身份验证这个方法即可。

测试类的方法
public class TestJdbcLogin{ 
@Test
public void testJDBCRealm() { //1、获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager Factory<org.apache.shiro.mgt.SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-jdbc-realm.ini"); //2、得到SecurityManager实例 并绑定给SecurityUtils org.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance(); SecurityUtils.setSecurityManager(securityManager); //3、得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证) Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123"); try { //4、登录,即身份验证 subject.login(token); } catch (IncorrectCredentialsException e) { //5、身份验证失败 e.printStackTrace(); System.out.println("密码错误"); }catch (DisabledAccountException e){ System.out.println("禁用的账户"); } Assert.assertEquals(true, subject.isAuthenticated()); //断言用户已经登录 //6、退出 subject.logout(); }
}

JdbcRealm 类

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.apache.shiro.realm.jdbc;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.sql.DataSource;
import org.apache.shiro.authc.AccountException;
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.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.config.ConfigurationException;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.JdbcUtils;
import org.apache.shiro.util.ByteSource.Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class JdbcRealm extends AuthorizingRealm {
    protected static final String DEFAULT_AUTHENTICATION_QUERY = "select password from users where username = ?";
    protected static final String DEFAULT_SALTED_AUTHENTICATION_QUERY = "select password, password_salt from users where username = ?";
    protected static final String DEFAULT_USER_ROLES_QUERY = "select role_name from user_roles where username = ?";
    protected static final String DEFAULT_PERMISSIONS_QUERY = "select permission from roles_permissions where role_name = ?";
    private static final Logger log = LoggerFactory.getLogger(JdbcRealm.class);
    protected DataSource dataSource;
    protected String authenticationQuery = "select password from users where username = ?";
    protected String userRolesQuery = "select role_name from user_roles where username = ?";
    protected String permissionsQuery = "select permission from roles_permissions where role_name = ?";
    protected boolean permissionsLookupEnabled = false;
    protected JdbcRealm.SaltStyle saltStyle;

    public JdbcRealm() {
        this.saltStyle = JdbcRealm.SaltStyle.NO_SALT;
    }

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public void setAuthenticationQuery(String authenticationQuery) {
        this.authenticationQuery = authenticationQuery;
    }

    public void setUserRolesQuery(String userRolesQuery) {
        this.userRolesQuery = userRolesQuery;
    }

    public void setPermissionsQuery(String permissionsQuery) {
        this.permissionsQuery = permissionsQuery;
    }

    public void setPermissionsLookupEnabled(boolean permissionsLookupEnabled) {
        this.permissionsLookupEnabled = permissionsLookupEnabled;
    }

    public void setSaltStyle(JdbcRealm.SaltStyle saltStyle) {
        this.saltStyle = saltStyle;
        if (saltStyle == JdbcRealm.SaltStyle.COLUMN && this.authenticationQuery.equals("select password from users where username = ?")) {
            this.authenticationQuery = "select password, password_salt from users where username = ?";
        }

    }

    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken upToken = (UsernamePasswordToken)token;
        String username = upToken.getUsername();
        if (username == null) {
            throw new AccountException("Null usernames are not allowed by this realm.");
        } else {
            Connection conn = null;
            SimpleAuthenticationInfo info = null;

            try {
                String salt;
                try {
                    conn = this.dataSource.getConnection();
                    String password = null;
                    salt = null;
                    switch(this.saltStyle) {
                    case NO_SALT:
                        password = this.getPasswordForUser(conn, username)[0];
                        break;
                    case CRYPT:
                        throw new ConfigurationException("Not implemented yet");
                    case COLUMN:
                        String[] queryResults = this.getPasswordForUser(conn, username);
                        password = queryResults[0];
                        salt = queryResults[1];
                        break;
                    case EXTERNAL:
                        password = this.getPasswordForUser(conn, username)[0];
                        salt = this.getSaltForUser(username);
                    }

                    if (password == null) {
                        throw new UnknownAccountException("No account found for user [" + username + "]");
                    }

                    info = new SimpleAuthenticationInfo(username, password.toCharArray(), this.getName());
                    if (salt != null) {
                        info.setCredentialsSalt(Util.bytes(salt));
                    }
                } catch (SQLException var12) {
                    salt = "There was a SQL error while authenticating user [" + username + "]";
                    if (log.isErrorEnabled()) {
                        log.error(salt, var12);
                    }

                    throw new AuthenticationException(salt, var12);
                }
            } finally {
                JdbcUtils.closeConnection(conn);
            }

            return info;
        }
    }

    private String[] getPasswordForUser(Connection conn, String username) throws SQLException {
        boolean returningSeparatedSalt = false;
        String[] result;
        switch(this.saltStyle) {
        case NO_SALT:
        case CRYPT:
        case EXTERNAL:
            result = new String[1];
            break;
        case COLUMN:
        default:
            result = new String[2];
            returningSeparatedSalt = true;
        }

        PreparedStatement ps = null;
        ResultSet rs = null;

        try {
            ps = conn.prepareStatement(this.authenticationQuery);
            ps.setString(1, username);
            rs = ps.executeQuery();

            for(boolean foundResult = false; rs.next(); foundResult = true) {
                if (foundResult) {
                    throw new AuthenticationException("More than one user row found for user [" + username + "]. Usernames must be unique.");
                }

                result[0] = rs.getString(1);
                if (returningSeparatedSalt) {
                    result[1] = rs.getString(2);
                }
            }
        } finally {
            JdbcUtils.closeResultSet(rs);
            JdbcUtils.closeStatement(ps);
        }

        return result;
    }

    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        if (principals == null) {
            throw new AuthorizationException("PrincipalCollection method argument cannot be null.");
        } else {
            String username = (String)this.getAvailablePrincipal(principals);
            Connection conn = null;
            Set<String> roleNames = null;
            Set permissions = null;

            try {
                conn = this.dataSource.getConnection();
                roleNames = this.getRoleNamesForUser(conn, username);
                if (this.permissionsLookupEnabled) {
                    permissions = this.getPermissions(conn, username, roleNames);
                }
            } catch (SQLException var11) {
                String message = "There was a SQL error while authorizing user [" + username + "]";
                if (log.isErrorEnabled()) {
                    log.error(message, var11);
                }

                throw new AuthorizationException(message, var11);
            } finally {
                JdbcUtils.closeConnection(conn);
            }

            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roleNames);
            info.setStringPermissions(permissions);
            return info;
        }
    }

    protected Set<String> getRoleNamesForUser(Connection conn, String username) throws SQLException {
        PreparedStatement ps = null;
        ResultSet rs = null;
        LinkedHashSet roleNames = new LinkedHashSet();

        try {
            ps = conn.prepareStatement(this.userRolesQuery);
            ps.setString(1, username);
            rs = ps.executeQuery();

            while(rs.next()) {
                String roleName = rs.getString(1);
                if (roleName != null) {
                    roleNames.add(roleName);
                } else if (log.isWarnEnabled()) {
                    log.warn("Null role name found while retrieving role names for user [" + username + "]");
                }
            }
        } finally {
            JdbcUtils.closeResultSet(rs);
            JdbcUtils.closeStatement(ps);
        }

        return roleNames;
    }

    protected Set<String> getPermissions(Connection conn, String username, Collection<String> roleNames) throws SQLException {
        PreparedStatement ps = null;
        LinkedHashSet permissions = new LinkedHashSet();

        try {
            ps = conn.prepareStatement(this.permissionsQuery);
            Iterator i$ = roleNames.iterator();

            while(i$.hasNext()) {
                String roleName = (String)i$.next();
                ps.setString(1, roleName);
                ResultSet rs = null;

                try {
                    rs = ps.executeQuery();

                    while(rs.next()) {
                        String permissionString = rs.getString(1);
                        permissions.add(permissionString);
                    }
                } finally {
                    JdbcUtils.closeResultSet(rs);
                }
            }
        } finally {
            JdbcUtils.closeStatement(ps);
        }

        return permissions;
    }

    protected String getSaltForUser(String username) {
        return username;
    }

    public static enum SaltStyle {
        NO_SALT,
        CRYPT,
        COLUMN,
        EXTERNAL;

        private SaltStyle() {
        }
    }
}

标红的查询语句正是shiro框架已经集成的查询语句,所以建表的时候要根据相应的表名建表

另外可以参考这篇文章:http://blog.51cto.com/luchunli/1828080


























原文地址:https://www.cnblogs.com/blogxiao/p/8509433.html