• SpringBoot与Shiro整合


    一、数据库设计

    ​  这里主要涉及到五张表:用户表,角色表(用户所拥有的角色),权限表(角色所涉及到的权限),用户-角色表(用户和角色是多对多的),角色-权限表(角色和权限是多对多的).表结构建立的sql语句如下:

    CREATE TABLE `module` (
      `mid` int(11) NOT NULL AUTO_INCREMENT,
      `mname` varchar(255) DEFAULT NULL,
      PRIMARY KEY (`mid`)
    ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of module
    -- ----------------------------
    INSERT INTO `module` VALUES ('1', 'add');
    INSERT INTO `module` VALUES ('2', 'delete');
    INSERT INTO `module` VALUES ('3', 'query');
    INSERT INTO `module` VALUES ('4', 'update');
    
    -- ----------------------------
    -- Table structure for module_role
    -- ----------------------------
    DROP TABLE IF EXISTS `module_role`;
    CREATE TABLE `module_role` (
      `rid` int(11) DEFAULT NULL,
      `mid` int(11) DEFAULT NULL,
      KEY `rid` (`rid`),
      KEY `mid` (`mid`),
      CONSTRAINT `mid` FOREIGN KEY (`mid`) REFERENCES `module` (`mid`),
      CONSTRAINT `rid` FOREIGN KEY (`rid`) REFERENCES `role` (`rid`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of module_role
    -- ----------------------------
    INSERT INTO `module_role` VALUES ('1', '1');
    INSERT INTO `module_role` VALUES ('1', '2');
    INSERT INTO `module_role` VALUES ('1', '3');
    INSERT INTO `module_role` VALUES ('1', '4');
    INSERT INTO `module_role` VALUES ('2', '1');
    INSERT INTO `module_role` VALUES ('2', '3');
    
    -- ----------------------------
    -- Table structure for role
    -- ----------------------------
    DROP TABLE IF EXISTS `role`;
    CREATE TABLE `role` (
      `rid` int(11) NOT NULL AUTO_INCREMENT,
      `rname` varchar(255) DEFAULT NULL,
      PRIMARY KEY (`rid`)
    ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of role
    -- ----------------------------
    INSERT INTO `role` VALUES ('1', 'admin');
    INSERT INTO `role` VALUES ('2', 'customer');
    
    -- ----------------------------
    -- Table structure for user
    -- ----------------------------
    DROP TABLE IF EXISTS `user`;
    CREATE TABLE `user` (
      `uid` int(11) NOT NULL AUTO_INCREMENT,
      `username` varchar(255) DEFAULT NULL,
      `password` varchar(255) DEFAULT NULL,
      PRIMARY KEY (`uid`)
    ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of user
    -- ----------------------------
    INSERT INTO `user` VALUES ('1', 'wulifu', '123456');
    INSERT INTO `user` VALUES ('2', 'root', '123456');
    
    -- ----------------------------
    -- Table structure for user_role
    -- ----------------------------
    DROP TABLE IF EXISTS `user_role`;
    CREATE TABLE `user_role` (
      `uid` int(11) DEFAULT NULL,
      `rid` int(11) DEFAULT NULL,
      KEY `u_fk` (`uid`),
      KEY `r_fk` (`rid`),
      CONSTRAINT `r_fk` FOREIGN KEY (`rid`) REFERENCES `role` (`rid`),
      CONSTRAINT `u_fk` FOREIGN KEY (`uid`) REFERENCES `user` (`uid`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of user_role
    -- ----------------------------
    INSERT INTO `user_role` VALUES ('1', '1');
    INSERT INTO `user_role` VALUES ('2', '2');
    View Code

    二、功能要求

    admin要求只有具有admin角色的用户才能访问,update需要有update权限的用户才能访问,login、loginUser都不做拦截。

    预期目标:

    wulifu是有admin角色和所有权限,所以用wulifu登录后,可以访问update和admin,但是不能访问guest;而root是customer角色,只有add和query权限,所以不能访问admin和update。

    三、添加依赖,配置文件

    1、springboot项目,项目结构如下:

    2、添加依赖

    <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.0.6.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
    
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
            <java.version>1.8</java.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>1.3.2</version>
            </dependency>
    
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <scope>runtime</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-core</artifactId>
                <version>1.2.3</version>
            </dependency>
            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-spring</artifactId>
                <version>1.2.3</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.0.20</version>
            </dependency>
            <!--常用的工具包-->
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-lang3</artifactId>
                <version>3.4</version>
            </dependency>
            <!--spring的上下文工具包-->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context-support</artifactId>
                <version>4.1.7.RELEASE</version>
            </dependency>
            <!--对jsp的处理-->
            <dependency>
                <groupId>org.apache.tomcat.embed</groupId>
                <artifactId>tomcat-embed-jasper</artifactId>
            </dependency>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>jstl</artifactId>
            </dependency>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
            </dependency>
        </dependencies>
    View Code

    3、application.yml

    server:
      port: 8010
      tomcat.uri-encoding: UTF-8
    
    spring:
      datasource:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://localhost:3306/shiro?characterEncoding=UTF-8
        username: root
        password: 123456
      mvc:
        view:
          prefix: /WEB-INF/jsp/
          suffix: .jsp
    mybatis:
      mapper-locations: mappers/*.xml
      # mapper.xml中的resultType中经常会用到一些自定义POJO,你可以用完全限定名来指定这些POJO的引用,例如
      #  <select id="getUsers" resultType="com.majing.learning.mybatis.entity.User">,
      # 又或者你可以通过在application.yml中指定POJO扫描包来让mybatis自动扫描到自定义POJO,如下:
      #  mybatis:type-aliases-package: com.majing.learning.mybatis.entity
      type-aliases-package: com.example.springbootshiro.pojo
    View Code

    三、项目设计

    1、pojo层

    User.java

    public class User implements Serializable {
        private Integer uid;
        private String username;
        private String password;
        private Set<Role> roles = new HashSet<>();
    }

    Role.java

    public class Role implements Serializable {
        private  Integer rid;
        private  String rname;
        private Set<Module> modules = new HashSet<>();
    }

    Module.java

    public class Module implements Serializable {
        private  Integer mid;
        private  String mname;
    }

    2、dao层

    UserMapper.java

    import com.example.springbootshiro.pojo.User;
    import org.springframework.stereotype.Repository;
    
    @Repository
    public interface UserMapper {
        User findByUserName(String username);
    }
    View Code

    UserMapper.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.example.springbootshiro.dao.UserMapper">
    
        <resultMap id="userMap" type="com.example.springbootshiro.pojo.User">
            <id property="uid" column="uid"/>
            <result property="username" column="username"/>
            <result property="password" column="password"/>
            <collection property="roles" ofType="com.example.springbootshiro.pojo.Role">
                <id property="rid" column="rid"/>
                <result property="rname" column="rname"/>
                <collection property="modules" ofType="com.example.springbootshiro.pojo.Module">
                    <id property="mid" column="mid"/>
                    <result property="mname" column="mname"/>
                </collection>
            </collection>
        </resultMap>
    
        <select id="findByUserName" parameterType="string" resultMap="userMap">
            SELECT u.*,r.*,m.* FROM user u
            inner join user_role ur on ur.uid=u.uid
            inner join role r on r.rid=ur.rid
            inner join module_role mr on mr.rid=r.rid
            inner join module m on mr.mid=m.mid
            WHERE username=#{username};
        </select>
    
    </mapper>
    View Code

    图中红框内可能会报错,但是依然可以正常运行。

    3、service层

    IUserService.Interface

    public interface IUserService {
        User findByUserName(String username);
    }
    View Code

    UserServiceImpl.java

    @Service("iUserService")
    public class UserServiceImpl implements IUserService {
        @Autowired
        private UserMapper userMapper;
    
        @Override
        public User findByUserName(String username) {
            return userMapper.findByUserName(username);
        }
    }
    View Code

    4、controller层

    TestController.java

    @Controller
    public class TestController {
    
        @RequestMapping("/login")
        public String login(){
            return "login";
        }
    
        @RequestMapping("/index")
        public String index(){
            return "index";
        }
    
        @RequestMapping("/unauthorized")
        public String unauthorized() {
            return "unauthorized";
        }
    
        /**
         * 拥有admin角色的人才能访问
         * @return
         */
        @RequestMapping("/admin")
        public String admin(){
            return "admin";
        }
    
        /**
         * 拥有update权限的人才能访问
         * @return
         */
        @RequestMapping("/update")
        public String update(){
            return "update";
        }
    
    
        @RequestMapping("/logout")
        public String logout(){
            Subject subject = SecurityUtils.getSubject();//取出当前验证主体
            if(subject != null){
                subject.logout(); //执行一次logout的操作,将session全部清空
            }
            return "login";
        }
    
        /**
         *  整个form表单的验证流程:
         *  将登陆的用户/密码传入UsernamePasswordToken,当调用subject.login(token)开始,
         *  调用Relam的doGetAuthenticationInfo方法,开始密码验证
         *  此时这个时候执行我们自己编写的CredentialMatcher(密码匹配器),
         *  执行doCredentialsMatch方法,具体的密码比较实现在这实现
         */
        @RequestMapping(value = "/loginUser")
        public String loginUser(@RequestParam("username") String username,
                                @RequestParam("password") String password,
                                HttpSession session) {
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
            Subject subject = SecurityUtils.getSubject();
            try {
                subject.login(token); //登陆成功的话,放到session中
                User user = (User) subject.getPrincipal();
                session.setAttribute("user", user);
                return "index";
            }catch (Exception e) {
                return "login";
            }
        }
    }
    View Code

    5、jsp页面

    login.jsp(登录页面)

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>login</title>
    </head>
    <body>
    <form action="/loginUser" method="post">
        <input type="text" name="username"> <br>
        <input type="password" name="password"> <br>
        <input type="submit" value="提交">
    </form>
    </body>
    </html>
    View Code

    index.jsp(登录成功后跳转的页面)

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>登录</title>
    </head>
    <body>
    <h1> 欢迎登录, ${user.username} </h1>
    </body>
    </html>
    View Code

    unauthorized.jsp (无权访问跳转的页面)

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    Unauthorized!
    </body>
    </html>
    View Code

    admin.jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>admin</title>
    </head>
    <body>
    admin!
    </body>
    </html>
    View Code

    update.jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>update</title>
    </head>
    <body>
    update!
    </body>
    </html>
    View Code

    四、配置Shiro

    1、核心配置类:ShiroConfiguration.java

    import org.apache.shiro.mgt.SecurityManager;
    import org.apache.shiro.spring.LifecycleBeanPostProcessor;
    import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
    import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
    import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
    import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import java.util.LinkedHashMap;
    
    @Configuration
    public class ShiroConfiguration {
    
        /**
         *  @Qualifier("XXX") Spring的Bean注入配置注解,该注解指定注入的Bean的名称,
         *  Spring框架使用byName方式寻找合格的bean,这样就消除了byType方式产生的歧义。
         */
        @Bean("shiroFilter")
        public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager manager) {
            ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
            System.out.println(bean);
            bean.setSecurityManager(manager);
    
            bean.setLoginUrl("/login"); //提供登录到url
            bean.setSuccessUrl("/index"); //提供登陆成功的url
            bean.setUnauthorizedUrl("/unauthorized");
    
            /**
             * 可以看DefaultFilter,这是一个枚举类,定义了很多的拦截器authc,anon等分别有对应的拦截器
             */
            //配置访问权限
            LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
            filterChainDefinitionMap.put("/index", "authc"); //代表着前面的url路径,用后面指定的拦截器进行拦截
            filterChainDefinitionMap.put("/login", "anon");
            filterChainDefinitionMap.put("/loginUser", "anon");
            filterChainDefinitionMap.put("/admin", "roles[admin]"); //admin的url,要用角色是admin的才可以登录,对应的拦截器是RolesAuthorizationFilter
            filterChainDefinitionMap.put("/update", "perms[update]"); //拥有update权限的用户才有资格去访问
            //filterChainDefinitionMap.put("/druid/**", "anon"); //所有的druid请求,不需要拦截,anon对应的拦截器不会进行拦截
            filterChainDefinitionMap.put("/**", "user"); //所有的路径都拦截,被UserFilter拦截,这里会判断用户有没有登陆
            bean.setFilterChainDefinitionMap(filterChainDefinitionMap);//设置一个拦截器链
    
            return bean;
        }
    
        /**
         * 定义安全管理器securityManager,注入自定义的realm
         * @param authRealm
         * @return
         */
        @Bean("securityManager")
        public SecurityManager securityManager(@Qualifier("authRealm") AuthRealm authRealm) {
            //这个DefaultWebSecurityManager构造函数,会对Subject,realm等进行基本的参数注入
            DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
            manager.setRealm(authRealm);//往SecurityManager中注入Realm,代替原本的默认配置
            return manager;
        }
    
    
        //自定义的Realm
        @Bean("authRealm")
        //@DependsOn("lifecycleBeanPostProcessor") //可选
        public AuthRealm authRealm(@Qualifier("credentialsMatcher") CredentialMatcher matcher) {
            AuthRealm authRealm = new AuthRealm();
            //这边可以选择是否将认证的缓存到内存中,现在有了这句代码就将认证信息缓存的内存中了
            //authRealm.setCacheManager(new MemoryConstrainedCacheManager());
            //最简单的情况就是明文直接匹配,然后就是加密匹配,这里的匹配工作则就是交给CredentialsMatcher来完成
            authRealm.setCredentialsMatcher(matcher);
            return authRealm;
        }
    
        /**
         * Realm在验证用户身份的时候,要进行密码匹配
         * 最简单的情况就是明文直接匹配,然后就是加密匹配,这里的匹配工作则就是交给CredentialsMatcher来完成
         * 支持任意数量的方案,包括纯文本比较、散列比较和其他方法。除非该方法重写,否则默认值为
         * @return
         */
        @Bean("credentialsMatcher")
        public CredentialMatcher credentialsMatcher() {
            CredentialMatcher credentialsMatcher = new CredentialMatcher();
            return credentialsMatcher;
        }
    
    
        /**
         * 配置shiro跟spring的关联
         * 以下AuthorizationAttributeSourceAdvisor,DefaultAdvisorAutoProxyCreator两个类是为了支持shiro注解
         * @param securityManager
         * @return
         */
        @Bean
        public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager securityManager) {
            AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
            advisor.setSecurityManager(securityManager);
            return advisor;
        }
    
        /**
         * Spring的一个bean , 由Advisor决定对哪些类的方法进行AOP代理
         * @return
         */
        @Bean
        public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
            DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
            creator.setProxyTargetClass(true);
            return creator;
        }
    
        /**
         * lifecycleBeanPostProcessor是负责生命周期的 , 初始化和销毁的类
         * (可选)
         * @return
         */
        @Bean("lifecycleBeanPostProcessor")
        public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
            return new LifecycleBeanPostProcessor();
        }
    
    }
    View Code

    这个SecurityManager的导包是org.apache.shiro.mgt.SecurityManager,不要导了java的包。

    2、自定义域:AuthRealm.java

    ​ 编写AuthRealm完成根据用户名去数据库的查询,并且将用户信息放入shiro中,供核心配置类:ShiroConfiguration调用。有认证与授权的方法。

    import com.example.springbootshiro.pojo.Module;
    import com.example.springbootshiro.pojo.Role;
    import com.example.springbootshiro.pojo.User;
    import com.example.springbootshiro.service.IUserService;
    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.springframework.beans.factory.annotation.Autowired;
    
    import java.util.*;
    
    //AuthenticatingRealm是抽象类,用于认证授权
    public class AuthRealm extends AuthorizingRealm {
    
        @Autowired
        private IUserService iUserService;
    
        /**
         * 用户授权
         * @param principals
         * @return
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            //获取前端输入的用户信息,封装为User对象
            User userweb = (User) principals.getPrimaryPrincipal();
            //获取前端输入的用户名
            String username = userweb.getUsername();
            //根据前端输入的用户名查询数据库中对应的记录
            User user = iUserService.findByUserName(username);
            if(user != null){
                SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
                //因为addRoles和addStringPermissions方法需要的参数类型是Collection
                //所以先创建两个collection集合
                Collection<String> rolesCollection = new HashSet<String>();
                Collection<String> perStringCollection = new HashSet<String>();
                //获取user的Role的set集合
                Set<Role> roles = user.getRoles();
                //遍历集合
                for (Role role : roles){
                    //将每一个role的name装进collection集合
                    rolesCollection.add(role.getRname());
                    //获取每一个Role的permission的set集合
                    Set<Module> permissionSet =  role.getModules();
                    //遍历集合
                    for (Module permission : permissionSet){
                        //将每一个permission的name装进collection集合
                        perStringCollection.add(permission.getMname());
                        System.out.println(permission.getMname());
                    }
                    //为用户授权
                    info.addStringPermissions(perStringCollection);
                }
                //为用户授予角色
                info.addRoles(rolesCollection);
                return info;
    
            }
            return null;
        }
    
        /**
         * 用于认证登录,认证接口实现方法,该方法的回调一般是通过subject.login(token)方法来实现的
         * AuthenticationToken 用于收集用户提交的身份(如用户名)及凭据(如密码):
         * AuthenticationInfo是包含了用户根据username返回的数据信息,用于在匹马比较的时候进行相互比较
         *
         * shiro的核心是java servlet规范中的filter,通过配置拦截器,使用拦截器链来拦截请求,如果允许访问,则通过。
         * 通常情况下,系统的登录、退出会配置拦截器。登录的时候,调用subject.login(token),token是用户验证信息,
         * 这个时候会在Realm中doGetAuthenticationInfo方法中进行认证。这个时候会把用户提交的验证信息与数据库中存储的认证信息,将所有的数据拿到,在匹配器中进行比较
         * 这边是我们自己实现的CredentialMatcher类的doCredentialsMatch方法,返回true则一致,false则登陆失败
         * 退出的时候,调用subject.logout(),会清除回话信息
         * @param token
         * @return
         * @throws AuthenticationException
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            //token携带了用户信息
            UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
            //获取前端输入的用户名
            String username  = usernamePasswordToken.getUsername();
            //根据用户名查询数据库中对应的记录
            User user = iUserService.findByUserName(username);
    
            /*//当前realm对象的name
            String realmName = getName();
            //盐值
            ByteSource credentialsSalt = ByteSource.Util.bytes(user.getUsername());
            //封装用户信息,构建AuthenticationInfo对象并返回
            AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(user, user.getPassword(),
                    credentialsSalt, realmName);*/
            return new SimpleAuthenticationInfo(user,user.getPassword(),this.getClass().getName());
        }
    
    }
    View Code

    3、数据库密码为明文时密码匹配类:CredentialMatcher.java

    import org.apache.shiro.authc.AuthenticationInfo;
    import org.apache.shiro.authc.AuthenticationToken;
    import org.apache.shiro.authc.UsernamePasswordToken;
    import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
    
    public class CredentialMatcher extends SimpleCredentialsMatcher {
        @Override
        public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
            UsernamePasswordToken utoken=(UsernamePasswordToken) token;
            //获得用户输入的密码:(可以采用加盐(salt)的方式去检验)
            String inPassword = new String(utoken.getPassword());
            //获得数据库中的密码
            String dbPassword=(String) info.getCredentials();
            //进行密码的比对
            return this.equals(inPassword, dbPassword);
        }
    }
    View Code

    4、数据库为加密加盐时

    authRealm引用的密码匹配需要更换。

    以下密码匹配直接写在核心配置类:ShiroConfiguration.java中

        /**
         * 密码校验规则HashedCredentialsMatcher
         * 这个类是为了对密码进行编码的 ,
         * 防止密码在数据库里明码保存 , 当然在登陆认证的时候 ,
         * 这个类也负责对form里输入的密码进行编码
         * 处理认证匹配处理器:如果自定义需要实现继承HashedCredentialsMatcher
         */
        @Bean("hashedCredentialsMatcher")
        public HashedCredentialsMatcher hashedCredentialsMatcher() {
            HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
            //指定加密方式为MD5
            credentialsMatcher.setHashAlgorithmName("MD5");
            //加密次数
            credentialsMatcher.setHashIterations(1024);
            credentialsMatcher.setStoredCredentialsHexEncoded(true);
            return credentialsMatcher;
        }
    View Code

    附上明文转密文的代码:

    public static void main(String[] args) {
            String hashAlgorithName = "MD5";
            String password = "登录时输入的密码";
            int hashIterations = 1;//加密次数
            ByteSource credentialsSalt = ByteSource.Util.bytes("登录时输入的用户名");
            Object obj = new SimpleHash(hashAlgorithName, password, credentialsSalt, hashIterations);
            System.out.println(obj);
        }
    View Code
  • 相关阅读:
    IDEA调试快捷键
    视频预览
    文件上传:简单的demo
    Java 运行时优化
    Java 类加载
    Java StringTable
    Java 为什么不用Vector
    C++ 查找函数
    JVM 垃圾回收
    JVM 直接内存
  • 原文地址:https://www.cnblogs.com/slivelove/p/9922666.html
Copyright © 2020-2023  润新知