shiro realizes login security authentication

shiro realizes login security authentication

The advantage of shiro is that there is no need to judge whether to log in or not in the code, and whether there is permission to execute. It realizes the control of permissions from the front-end page to the background code is very flexible and convenient

The traditional login authentication method is that after obtaining the account and password entered by the user from the front-end page, go directly to the database to check whether the account and password match and exist.

The authentication method of shiro is to obtain the account and password entered by the user from the front-end page, and then pass it to a UsernamePasswordToken object, which is a token.

Then pass the token to the subject, and the subject will call the custom realm,

What realm does is to use the user name entered by the front-end user to query the database for a record (only use the user name to check, and the query will return the user name and password), and then compare the two passwords. If they are inconsistent, an exception will appear.

That is to say, if subject.login(token); does not throw an exception, it means that the username and password match, indicating that the login is successful

1. Introduce shiro dependency in pom.xml

    <!-- 引入shiro框架的依赖 -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-all</artifactId>
            <version>1.2.2</version>
        </dependency>

2. Configure the filter in web.xml

<!-- 配置spring提供的用于整合shiro框架的过滤器 -->
  <filter>
    <filter-name>shiroFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>shiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

3. Configure the Bean of DelegatingFilterProxy in applicationContext.xml

<!-- 配置一个shiro框架的过滤器工厂bean,用于创建shiro框架的过滤器 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!-- 注入安全管理器对象 -->
        <property name="securityManager" ref="securityManager"/>
        <!-- 注入登录页面访问URL -->
        <property name="loginUrl" value="/login.jsp"/>
        <!-- 注入权限不足提供页面访问URL -->
        <property name="unauthorizedUrl" value="/unauthorized.jsp"/><!-- 已经登录,但是用户没有权限的时候才跳转 -->
        <!-- 配置URL拦截规则 -->
        <property name="filterChainDefinitions">
            <value>
                /css/** = anon
                /js/** = anon
                /images/** = anon
                /validatecode.jsp* = anon
                /login.jsp* = anon
                /userAction_login.action = anon
                /page_base_staff.action = perms["staff"]
                /** = authc<!-- 其他设置用户认证才能使用-->
            </value>
        </property>
    </bean>
    
    <!-- 注册安全管理器 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"></bean>

Common Filters

常用过滤器:
anon:例子/admins/**=anon表示可以匿名访问
authc:例如/admins/user/**=authc表示需要认证才能使用,没有参数
perms:例子/page_base_staff.action = perms["staff"],当前用户需要有staff权限才可以访问。
roles:例子/admins/user/**=roles[admin],当前用户是否有这个角色权限。

Writing the login method

traditional login method

    
    public String login(){
                //调用service层查询账号和密码是否一致
                UserBean user= userService.login(model);
                if(user!=null)
                {
                    return "index";
                }
                else
                {
                    addActionError("用户名和密码不匹配...");
                    return "login";
                }
                
            }
    }

Shiro's login authentication method

    public String login(){           
                if((!StringUtils.isBlank(checkcode))&&key.contentEquals(checkcode) )
                {
                    Subject subject = SecurityUtils.getSubject();//获取当前用户对象
                    //生成令牌(传入用户输入的账号和密码)
                    UsernamePasswordToken token=new UsernamePasswordToken(model.getUsername(),MD5Utils.md5(model.getPassword()));
                    
                    //认证登录
                    try {
                        //这里会加载自定义的realm
                subject.login(token);//把令牌放到login里面进行查询,如果查询账号和密码时候匹配,如果匹配就把user对象获取出来,失败就抛异常
                UserBean user= (UserBean) subject.getPrincipal();//获取登录成功的用户对象(以前是直接去service里面查)
                ServletActionContext.getRequest().getSession().setAttribute("user", user);
                        return "index";
                    } catch (Exception e) {
                        //认证登录失败抛出异常
                        addActionError("用户名和密码不匹配...");
                        return "login";
                    }
                }
        }
    
    
                    

Writing custom realm

public class Bos_realm extends AuthorizingRealm {

    @Resource
    private IUserDao<UserBean> userDao;
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        
    UsernamePasswordToken usertoken=(UsernamePasswordToken) token;//获取令牌(里面存放new UsernamePasswordToken放入的账号和密码)
      
        //得到账号和密码
        String username = usertoken.getUsername();
        
        UserBean findusername = userDao.findByusername(username);//去sql查询用户名是否存在,如果存在返回对象(账号和密码都有的对象)
      
        if(findusername!=null)//如果用户名存在
        {
            //参数1.用户认证的对象(subject.getPrincipal();返回的对象),
            //参数2.从数据库根据用户名查询到的用户的密码
            //参数3.把当前自定义的realm对象传给SimpleAuthenticationInfo,在配置文件需要注入
            AuthenticationInfo Info = new SimpleAuthenticationInfo(findusername, findusername.getPassword(),this.getName());
            return Info;
        
        }else
        {
            return null;
        }
    }

}

Inject custom realm in security manager

    <!-- 注册安全管理器 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    <!-- 注入realm到安全管理器进行密码匹配 -->
    <property name="realm" ref="BosRealm"></property>
    </bean>
    <!-- 自定义的realm -->
    <bean id="BosRealm" class="com.itheima.bos.action.Bos_realm"></bean>

Four ways to add permissions

1_url

Add blocking rules inside

<!-- 配置URL拦截规则 -->
        <property name="filterChainDefinitions">
            <value>
                /css/** = anon
                /js/** = anon
                /images/** = anon
                /validatecode.jsp* = anon
                /login.jsp* = anon
                /User_login.action= anon
                /page_base_staff.action = perms["staff"] <!-- 拦截page_base_staff.action这个方法必须有staff权限才能使用 -->
                /** = authc
            </value>
        </property>

2_Annotation

It needs to be configured to turn on annotation scanning in order to use

Turn on annotation scanning with added permissions

    <bean id="defaultAdvisorAutoProxyCreator" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
        <!-- 配置强制使用cglib方式为Action创建代理对象 -->
        <property name="proxyTargetClass" value="true"/>
    </bean>
    
    <!-- 配置shiro框架的切面类 -->
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"/>
//把订单设置为作废
    @RequiresPermissions("staff.delete")//为delete这个方法添加staff.delete权限
    public String delete()
    {
        //得到id
        staffService.deleteBatch(ids);
        return "staff";
    }

3_jsp page

Need to import shiro tag library

<%@ taglib uri="http://shiro.apache.org/tags"  prefix="shiro"%>
    /* 有staff权限才能显示此按钮 */
<shiro:hasPermission name="staff1">
    {
        id : 'button-delete',
        text : '作废',
        iconCls : 'icon-cancel',
        handler : doDelete
    },
    </shiro:hasPermission>

4_code (almost useless)

Just add two lines of code to the code where you want to set permissions

    //修改
    public String edit()
    {
        Subject subject = SecurityUtils.getSubject();
        subject.checkPermission("staff.edit");//要运行此方法下面的代码,必须要拥有staff.edit的权限
        //更新model
        staffService.update(model);
        return "staff";
    }

Authorize

Manual authorization and authentication

Because there are too many permissions to be authorized, a permission table is required

public class Bos_realm extends AuthorizingRealm {

    @Resource
    private IUserDao<UserBean> userDao;
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {

      
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addStringPermission("staff");//为page_base_staff.action请求授权staff权限
        info.addStringPermission("staff.delete");//为page_base_staff.action请求授权staff权限
        info.addStringPermission("staff.edit");
        return info;
     
    }

    //用户的登录认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //这里添加认证代码
      
      UsernamePasswordToken usertoken=(UsernamePasswordToken) token;//获取令牌(里面存放的有账号和密码)
        
        //查询用户名是否存在
        String username = usertoken.getUsername();
        
        UserBean findusername = userDao.findByusername(username);//去sql查询用户名是否存在
        if(findusername!=null)//如果用户名存在
        {
            //参数1.用户认证的对象(subject.getPrincipal();返回的对象),
            //参数2.从数据库根据用户名查询到的用户的密码
            //参数3.把当前自定义的realm对象传给SimpleAuthenticationInfo,在配置文件需要注入
            AuthenticationInfo Info = new SimpleAuthenticationInfo(findusername, findusername.getPassword(),this.getName());
            return Info;
        
        }else
        {
            return null;
        }
      

}

Traverse database authorization

Get the currently logged in user, go to the database to query all the permissions of the current user, and then add

    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();       

        //获取当前用户
        UserBean findusername = session.get......;
        
        //结果集
        List<AuthFunction> functionList =null;

        //去sql查询当前用户的权限
        if("admin".equals(findusername.getUsername()))//如果是管理员,获取所有权限
        {
             functionList = functionDao.findAll();
        }else
        {
            String hql = "SELECT DISTINCT f FROM AuthFunction f LEFT OUTER JOIN f.authRoles r LEFT              OUTER JOIN r.userBeans u WHERE u.id = ?";
            functionList = functionDao.findByHQL(hql,findusername.getId());
        }
        
        //遍历结果集授权
        for (AuthFunction authFunction : functionList) {
            info.addStringPermission(authFunction.getCode());
        }

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325753554&siteId=291194637