zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    el-select下拉框选项太多导致卡顿,使用下拉框分页来解决
    vue+elementui前端添加数字千位分割
    Failed to check/redeclare auto-delete queue(s)
    周末啦,做几道面试题放松放松吧!
    idea快捷键
    解决flink运行过程中报错Could not allocate enough slots within timeout of 300000 ms to run the job. Please make sure that the cluster has enough resources.
    用.net平台实现websocket server
    MQTT实战3
    Oracle 查看当前用户下库里所有的表、存储过程、触发器、视图
    idea从svn拉取项目不识别svn
  • 原文地址:https://www.cnblogs.com/slivelove/p/9922666.html
Copyright © 2011-2022 走看看