【Shiro】Shiro与web集成

与web项⽬集成后,shiro的⼯作模式如下:

如上:ShiroFilter拦截所有请求,对于请求做访问控制
如请求对应的功能是否需要有 认证的身份,是否需要某种⻆⾊,是否需要某种权限等。

  • 如果没有做 身份认证,则将请求强制跳转到登录⻚⾯。
    如果没有充分的⻆⾊或权限,则将请求跳转到权限不⾜的⻚⾯。
  • 如果校验成功,则执⾏请求的业务逻辑

1. pom依赖

<!-- ============ Servlet ============ -->
<dependency>
    <groupId>javax.servlet.jsp</groupId>
    <artifactId>jsp-api</artifactId>
    <version>2.1</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency>
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <scope>provided</scope>
</dependency>
<!-- ============== SpringMVC ============== -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>4.3.6.RELEASE</version>
</dependency>
<!-- ============ shiro ============ -->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-core</artifactId>
    <version>1.4.0</version>
</dependency>
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-web</artifactId>
    <version>1.4.0</version>
</dependency>
<!-- ============ log ============ -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.12</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.12</version>
</dependency>
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.16</version>
</dependency>

2. 基础代码

package com.siyi.controller;

import com.siyi.pojo.User;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/user")
public class UserController {

    @GetMapping("/login")
    public String login(){
        System.out.println("goto login page");
        return "login";
    }

    @PostMapping("/login")
    public String loginLogic(User user){
        System.out.println("login logic");
        //获取subject 调用login
        Subject subject = SecurityUtils.getSubject();
        //创建用于登录的令牌
        UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword());
        //登录失败会抛出异常,则交由异常解析器处理
        subject.login(token);
        return "index";
    }

    @GetMapping("/all")
    public String queryAllUsers(){
        System.out.println("query all users");
        return "index";
    }

    @RequestMapping("/perms/error")
    public String permsError(){
        System.out.println("权限不足");
        return "perm_error";
    }
}

3. 配置

3.1 web.xml

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">

    <display-name>Archetype Created Web Application</display-name>

    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:mvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <!-- 接收所有请求,以通过请求路径 识别是否需要 安全校验,如果需要则触发安全校验
    做访问校验时,会遍历过滤器链。(链中包含shiro.ini中urls内使⽤的过滤器)
    会通过ThreadContext在当前线程中绑定⼀个subject和SecurityManager,供请求内使⽤
    可以通过SecurityUtils.getSubject()获得Subject
    1.在项目的最外层构建访问控制层
    2.在启动时,初始化shiro环境
    -->
    <filter>
        <filter-name>shiroFilter</filter-name>
        <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>shiroFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- 在项⽬启动时,加载web-info 或 classpath下的 shiro.ini ,并构建WebSecurityManager。
        构建所有配置中使⽤的过滤器链(anon,authc等),ShiroFilter会获取此过滤器链
    -->
    <listener>
        <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
    </listener>
    <!-- ⾃定义ini⽂件名称和位置,默认会取寻找classpath下的 shiro.ini 。
    <context-param>
        <param-name>shiroConfigLocations</param-name>
        <param-value>classpath:shiro9.ini</param-value>
    </context-param>
    -->

    <filter>
        <filter-name>encoding</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encoding</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

3.2 shiro.ini

[users]
zhangsan=123,admin
lisi=456,manager,seller
wangwu=789,clerk

[roles]
admin=*
clerk=user:query,user:detail:query
manager=user:*

[main]
#没有身份认证时,跳转地址
shiro.loginUrl = /user/login
#⻆⾊或权限校验不通过时,跳转地址
shiro.unauthorizedUrl=/user/perms/error
#登出后的跳转地址,回⾸⻚
shiro.redirectUrl=/

[urls]
# 如下格式:"访问路径 = 过滤器"
#【1.ant路径:? * ** 细节如下】
# /user/login/page , /user/login/logic 是普通路径
# /user/* 代表/user后还有⼀级任意路径 : /user/a , /user/b , /user/c , /user/xxxxxxxxxxx
# /user/** 代表/user后还有任意多级任意路径: /user/a , /user/a/b/c , /user/xxxx/xxxxxx/xxxxx
# /user/hello? 代表hello后还有⼀个任意字符: /user/helloa , /user/hellob , /user/hellox

#【2.过滤器,细节如下】
# anon => 不需要身份认证
# authc => 指定路径的访问,会验证是否已经认证身份,如果没有则会强制转发到 最上⾯配置的loginUrl上
# ( ops:登录逻辑本身千万不要被认证拦截,否则⽆法登录 )
# logout => 访问指定的路径,可以登出,不⽤定义handler。
# roles["manager","seller"] => 指定路径的访问需要subject有这两个⻆⾊
# perms["user:update","user:delete"] => 指定路径的访问需要subject有这两个权限
/user/login/page = anon
/user/login/logic = anon
/user/query = authc
/user/update = authc,roles["manager","seller"]
/user/delete = authc, perms["user:update","user:delete"]
/user/logout = logout  # 内置的过滤器,直接登出
#其余路径都需要身份认证【⽤此路径需谨慎】
/** = authc
#【3.注意】
#  以上的就是过滤器链条
# url的匹配,是从上到下匹配,⼀旦找到可以匹配的则停⽌,所以,通配范围⼤的url要往后放,
# 如"/user/delete" 和 "/user/**"

3.3 其他默认过滤器


过滤器的名称实际上是一个枚举类型:每个名称对应一个过滤器。

package org.apache.shiro.web.filter.mgt;

import org.apache.shiro.util.ClassUtils;
import org.apache.shiro.web.filter.authc.*;
import org.apache.shiro.web.filter.authz.*;
import org.apache.shiro.web.filter.session.NoSessionCreationFilter;

import javax.servlet.Filter;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import java.util.LinkedHashMap;
import java.util.Map;

public enum DefaultFilter {

    anon(AnonymousFilter.class),
    authc(FormAuthenticationFilter.class),
    authcBasic(BasicHttpAuthenticationFilter.class),
    logout(LogoutFilter.class),
    noSessionCreation(NoSessionCreationFilter.class),
    perms(PermissionsAuthorizationFilter.class),
    port(PortFilter.class),
    rest(HttpMethodPermissionFilter.class),
    roles(RolesAuthorizationFilter.class),
    ssl(SslFilter.class),
    user(UserFilter.class);

    private final Class<? extends Filter> filterClass;

    private DefaultFilter(Class<? extends Filter> filterClass) {
        this.filterClass = filterClass;
    }

    public Filter newInstance() {
        return (Filter) ClassUtils.newInstance(this.filterClass);
    }

    public Class<? extends Filter> getFilterClass() {
        return this.filterClass;
    }

    public static Map<String, Filter> createInstanceMap(FilterConfig config) {
        Map<String, Filter> filters = new LinkedHashMap<String, Filter>(values().length);
        for (DefaultFilter defaultFilter : values()) {
            Filter filter = defaultFilter.newInstance();
            if (config != null) {
                try {
                    filter.init(config);
                } catch (ServletException e) {
                    String msg = "Unable to correctly init default filter instance of type " +
                            filter.getClass().getName();
                    throw new IllegalStateException(msg, e);
                }
            }
            filters.put(defaultFilter.name(), filter);
        }
        return filters;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值