스프링 부팅 2 + 시로 + JWT 달성 통합 권한 관리

빈의 년 후에, 나는 아파치 시로 연구 시간을 보냈다. 샘플 코드 주소

https://github.com/CodingSoldier/java-learn/tree/master/project/shiro/shiro-jwt

당신이 아파치 시로을 이해하지 못한다면, 나는 나의 학습 경로를 제공합니다 :

(1) 첫 번째 교훈은 뮤 네트워크 "무료 자습서를 배울 수 시로 보안 프레임 워크 시작하기 " https://www.imooc.com/learn/977을 .

2, 다음 튜토리얼 수업 뮤 네트워크 배운 충전 "자바 개발 기업 권한 관리 시스템을,"오직 배운 제 3 장 아파치 시로 권한 프레임 워크 이론과 실습 https://coding.imooc.com/class/chapter/149.html #anchor .

3, 마지막 학교 시로 문서, 12 문서의 중국어 버전이, 번역 수준은 조금 더 나은 구글 번역 모음에 매우 좋지 않다. https://www.ctolib.com/docs/sfile/apache-shiro-reference/

스프링 부팅 2 + 시로 + JWT 통합

pom.xml 파일 의존

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!--spring-boot与shiro的整合包-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-web-starter</artifactId>
            <version>1.4.2</version>
        </dependency>

        <!--jwt依赖-->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.2.0</version>
        </dependency>

shiro으로 subject, principals :

주제는, 보안 용어입니다 보안 응용 프로그램의 특정 사용자를 의미한다 "보기." 시로 주제 인스턴스는 하나의 응용 프로그램 및 사용자 작업의 안전 상태를 나타냅니다. 대부분의 경우 대상은 사용자가에서 웹 응용 프로그램의 경우, 그것은 클라이언트가 될 수 있습니다.

교장 (정체성)의 주제는 "ID 속성." 예를 들어 userId를, 사용자 이름, 클라이언트 ID. 또 다른 보안 프레임 워크 봄 보안 사용자도 사용자를 고유하게 식별하는 데 사용됩니다.

다음 코드에서 이해 될 수있다

    @Test
    public void test1(){

        SimpleAccountRealm sar = new SimpleAccountRealm();
        sar.addAccount("username01", "pwd01");

        DefaultSecurityManager dsm = new DefaultSecurityManager();
        dsm.setRealm(sar);

        SecurityUtils.setSecurityManager(dsm);
        Subject subject = SecurityUtils.getSubject();
        System.out.println("subject未登陆,principals是null: "+subject.getPrincipals());

        UsernamePasswordToken token = new UsernamePasswordToken("username01", "pwd01");

        subject.login(token);
        System.out.println("subject登陆成功后,principals是UsernamePasswordToken中的第一个参数: "+subject.getPrincipals());

    }

왜 교장은 UsernamePasswordToken 그것의 이름입니다 정체성의 성공적인 착륙 대상은 속성 후?

UsernamePasswordToken 소스 인터페이스 커버 해, getPrincipal 인증 토큰 () 메소드 때문에

공공 객체 해, getPrincipal () {
    반환 this.getUsername ();
}

이 방법은 사용자 이름 UsernamePasswordToken 첫 번째 매개 변수를 반환합니다.

기본값 사용 UsernamePasswordToken 착륙, 시로 것이다 교장과 인증 상태의 피사체가 세션에 저장되어 있지만 세션은 자바 덜 일반적인, 그리고 더 일반적으로 사용되는 토큰있다. 본원 JWT 토큰 생성 사용될 것이다.

여러 개념은 당신이 알 필요가 있습니다 :

시로 사용자 인증 및 사용자 인증은 별도. 사용자 인증 (상륙으로 이해 될 수있다)을 좀 두 단어처럼 보인다 권한 부여라는 인증, 권한 부여 사용자를했다. 인증 및 관련 인증, 권한 부여를 나타냅니다 클래스 나 메소드를 공격하고, 권한 부여는 관련이 발생 나타냅니다 때.

영역 등은 사용자, 역할, 권한의 성분으로서, 클라이언트의 데이터 보안에 저장되고, 그것은 DAO로 이해 될 수있다.

시로 제 필터로 요청을 인터셉트하고, 사용자 인증, 권한 부여 정보를 취득하는 영역을 요구한다.

여기에 일부 코드 하이라이트

subject.login (토큰) 수신 파라미터 방법은 인증 토큰 새로운 상속 JwtToken 인증 토큰이다.

public class JwtToken implements AuthenticationToken {
    private String token;
    public JwtToken(String token) {
        this.token = token;
    }

    // token作为principal,
    @Override
    public Object getPrincipal() {
        return this.token;
    }

    // 由于getPrincipal没返回username,而是返回token,所以credentials设置为空字符串即可
    @Override
    public Object getCredentials() {
        return Constant.CREDENTIALS_EMPTY;
    }
}

BasicHttpAuthenticationFilter 상속 새로운 JwtFilter는, 인증 단어를 참조,이 필터의 역할을 알아야 할 모든 사람이 사용자 인증입니다.

@Slf4j
public class JwtFilter extends BasicHttpAuthenticationFilter {

    @Override
    protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
        // 获取请求头Authorization的值
        String authorization = getAuthzHeader(request);
        return new JwtToken(authorization);
    }

    /**
     * 执行登录操作
     * 大部分代码跟父类一样,不同之处是catch到异常后返回自定义异常给前端
     */
    @Override
    protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
        AuthenticationToken token = this.createToken(request, response);
        if (token == null) {
            String msg = "createToken method implementation returned null. A valid non-null AuthenticationToken must be created in order to execute a login attempt.";
            throw new IllegalStateException(msg);
        } else {
            try {
                Subject subject = this.getSubject(request, response);
                subject.login(token);
                return this.onLoginSuccess(token, subject, request, response);
            } catch (AuthenticationException e) {
                Result result = Result.fail("用户认证异常");
                if (e.getCause() instanceof CustomException){
                    CustomException customException = (CustomException)e.getCause();
                    result = Result.fail(customException.getCode(), customException.getMessage());
                }
                WebUtil.sendResponse(response, result);
                return false;
            }
        }
    }

    /**
     * 身份认证未通过,执行此方法
     * 返回true,继续处理请求
     * 返回false,不继续处理请求,结束过滤器链
     * BasicHttpAuthenticationFilter源码中也是在onAccessDenied()方法内调用executeLogin
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        boolean r;
        String authorization = getAuthzHeader(request);
        if (StringUtils.isEmpty(authorization)){
            WebUtil.sendResponse(response, Result.fail(Constant.CODE_TOKEN_ERROR,"无token"));
            r = false;
        }else {
            r = executeLogin(request, response);
        }
        return r;
    }
    
}

사용자 인터페이스에 대한 액세스 권한이없는 경우 시로 기본 권한 필터, PermissionsAuthorizationFilter이며, 정보가 비우호적의 전면에 반환, 우리는 CustomPermissionsAuthorizationFilter가 PermissionsAuthorizationFilter 전면에 사용자 정의 메시지를 반환 상속 물품. 권한 부여는이 필터가 인증 된 사용자와 연결되어 있는지 알고,이 단어를 참조하십시오.

@Slf4j
public class CustomPermissionsAuthorizationFilter extends PermissionsAuthorizationFilter {

    /**
     * 用户无权访问url时,此方法会被调用
     * 默认实现为org.apache.shiro.web.filter.authz.AuthorizationFilter#onAccessDenied()
     * 覆盖父类的方法,返回自定义信息给前端
     *
     * 接口doc上说:
     *    AuthorizationFilter子类(权限授权过滤器)的onAccessDenied()应该永远返回false,那么在onAccessDenied()内就必然要发送response响应给前端,不然前端就收不到任何数据
     *    AuthenticationFilter、AuthenticatingFilter子类(身份认证过滤器)的onAccessDenied()的返回值则没有限制
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
        WebUtil.sendResponse(response, Result.fail("权限不足"));
        return false;
    }

}

JwtRealm를 구축하려면

public class JwtRealm extends AuthorizingRealm {

    private UserService userService;

    /**
     * 最好保持单例
     * JwtRealm可以不交给spring管理,在创建JwtRealm的时候需要创建者传递参数UserService
     */
    public JwtRealm(UserService userService) {
        this.userService = userService;

        /**
         * 启动认证缓存,默认是false。源码如下
         * org.apache.shiro.realm.AuthenticatingRealm#AuthenticatingRealm()
         *     this.authenticationCachingEnabled = false;
         */
        this.setAuthenticationCachingEnabled(true);

        /**
         * 启动授权缓存,默认就是true,代码如下
         * org.apache.shiro.realm.AuthorizingRealm#AuthorizingRealm()
         *     this.authorizationCachingEnabled = true;
         */
        // this.setAuthorizationCachingEnabled(true);

        // 设置缓存管理器,使用shiro自带的MemoryConstrainedCacheManager即可
        this.setCacheManager(new MemoryConstrainedCacheManager());

    }

    // subject.login(token)方法中的token是JwtToken时,调用此Realm的doGetAuthenticationInfo
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JwtToken;
    }

    /**
     * 认证用户
     * 本方法被 org.apache.shiro.realm.AuthenticatingRealm#getAuthenticationInfo()调用
     *    AuthenticationInfo info = this.getCachedAuthenticationInfo(token);
     *    如果通过token在缓存中获取到用户认证,就不调用本方法
     *
     * 补充一点:用户认证接口往往只传递principals信息,不传credentials。在spring security中也是这种思路
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws CustomAuthenticationException {
        String token = (String) authenticationToken.getPrincipal();
        if (StringUtils.isEmpty(token)){
            throw new CustomAuthenticationException("token为空");
        }
        String username = JWTUtil.getUsername(token);
        User user = userService.getUser(username);
        if (user == null){
            throw new CustomAuthenticationException("无此用户");
        }
        /**
         * token无效,抛出异常
         * MyControllerAdvice捕获MyException异常后,将Constant.CODE_TOKEN_ERROR返回给前端,前端收到此code后跳转登录页
         */
        if (!JWTUtil.verify(token, username, user.getPassword())){
            throw new CustomAuthenticationException(Constant.CODE_TOKEN_ERROR, "token无效,请重新登录");
        }
        if (JWTUtil.isExpired(token)){
            throw new CustomAuthenticationException(Constant.CODE_TOKEN_ERROR, "token无效,请重新登录");
        }
        return new SimpleAuthenticationInfo(token, Constant.CREDENTIALS_EMPTY, this.getName());
    }

    /**
     * 用户授权
     * 本方法被 org.apache.shiro.realm.AuthorizingRealm#getAuthorizationInfo() 调用
     *     Cache<Object, AuthorizationInfo> cache = this.getAvailableAuthorizationCache();
     *     如果获取到缓存,就通过cache.get(key)获取授权数据,key就是principal
     *
     *     若无缓存,在调用了本方法后,会将本方法返回的AuthorizationInfo添加到缓存中
     *     cache.put(key, info);
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        String username = JWTUtil.getUsername(principalCollection.getPrimaryPrincipal().toString());
        User user = userService.getUser(username);

        SimpleAuthorizationInfo sai = new SimpleAuthorizationInfo();

        List<String> roleList = new ArrayList<>();
        List<String> permissionList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(user.getRoleList())){
            for (Role role:user.getRoleList()){
                roleList.add(role.getName());
                if (!CollectionUtils.isEmpty(role.getPermissionList())){
                    for (Permission permission:role.getPermissionList()){
                        permissionList.add(permission.getName());
                    }
                }
            }
        }
        sai.addRoles(roleList);
        sai.addStringPermissions(permissionList);

        return sai;
    }
}

시로 구성 클래스

@Configuration
public class ShiroConfig {

    // 使用@Lazy避免UserService为空
    @Lazy
    @Autowired
    UserService userService;

    // 创建jwtRealm
    @Bean
    public JwtRealm jwtRealm(){
        return new JwtRealm(userService);
    }

    @Bean
    public DefaultWebSecurityManager securityManager(@Qualifier("jwtRealm") JwtRealm jwtRealm){
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        // 设置realm
        manager.setRealm(jwtRealm);

        /**
         * 禁止session持久化存储
         * 一定要禁止session持久化。不然清除认证缓存、授权缓存后,shiro依旧能从session中读取到认证信息
         */
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        manager.setSubjectDAO(subjectDAO);

        return manager;
    }

    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();

        factoryBean.setSecurityManager(securityManager);

        //添加filter,factoryBean.getFilters()获取到的是引用,可直接添加值
        factoryBean.getFilters().put("jwt", new JwtFilter());
        factoryBean.getFilters().put("customPerms", new CustomPermissionsAuthorizationFilter());

        /**
         * factoryBean.getFilterChainDefinitionMap();默认是size=0的LinkedHashMap
         */
        Map<String, String> definitionMap = factoryBean.getFilterChainDefinitionMap();

        /**
         * definitionMap是一个LinkedHashMap,是一个链表结构
         * put的顺序很重要,当/open/**匹配到请求url后,将不再检查后面的规则
         * 官方将这种原则称为 FIRST MATCH WINS
         * https://waylau.gitbooks.io/apache-shiro-1-2-x-reference/content/III.%20Web%20Applications/10.%20Web.html
         */
        definitionMap.put("/open/**", "anon");

        /**
         * 由于禁用了session存储,shiro不会存储用户的认证状态,所以在接口授权之前要先认证用户,不然CustomPermissionsAuthorizationFilter不知道用户是谁
         * 实际项目中可以将这些接口权限规则放到数据库中去
         */
        definitionMap.put("/user/add", "jwt, customPerms["+userService.getUserAdd().getName()+"]");
        definitionMap.put("/user/delete", "jwt, customPerms["+userService.getUserDelete().getName()+"]");
        definitionMap.put("/user/edit", "jwt, customPerms["+userService.getUserEdit().getName()+"]");
        definitionMap.put("/user/view", "jwt, customPerms["+userService.getUserView().getName()+"]");
        definitionMap.put("/test/other", "jwt, customPerms["+userService.getTestOther().getName()+"]");
        definitionMap.put("/role/permission/edit", "jwt, customPerms["+userService.getRolePermisssionEdit().getName()+"]");

        // 前面的规则都没匹配到,最后添加一条规则,所有的接口都要经过com.example.shirojwt.filter.JwtFilter这个过滤器验证
        definitionMap.put("/**", "jwt");

        factoryBean.setFilterChainDefinitionMap(definitionMap);

        return factoryBean;
    }
}

먼저 자신의 컴퓨터에서 실행, 내 github의 다운로드에 코드를 사람을 부탁드립니다.

시로 인증, 권한 부여는이 프로젝트에 처리

착륙 인터페이스 만들기

@RestController
@Slf4j
@RequestMapping("/open")
public class OpenApiCtrl {
    @Autowired
    UserService userService;

    /**
     * 登陆
     * 开放接口,不使用shiro拦截,生成令牌并返回给前端
     * 用户名             密码
     * admin           admin-pwd
     * cudrOtherUser   cudrOtherUser-pwd
     * viewUser        viewUser-pwd
     */
    @PostMapping("/login")
    public Result openLogin(@RequestBody User userVo){
        String username = userVo.getUsername();
        String password = userVo.getPassword();

        // 用户名密码校验
        User user = userService.getUser(username);
        if (user == null){
            throw new CustomException("无此用户");
        }
        if (!user.getPassword().equals(new Md5Hash(password).toString())){
            throw new CustomException("用户名或密码错误");
        }

        // 生成令牌
        String token = JWTUtil.sign(username, user.getPassword());

        /**
         * 在登陆接口中就执行shiro用户认证,用于测试不禁用session存储的情形
         */
        //JwtToken jwtToken = new JwtToken(token);
        //Subject subject = SecurityUtils.getSubject();
        //subject.login(jwtToken);

        return Result.success(token);
    }

}

토큰의 프런트 엔드는 토큰을 얻기 위해, 다음 요청은 인증 헤더 = 토큰에 배치됩니다

그런 다음 요청을 전송

컬 --location --request GET '로컬 호스트 : 8080 / 사용자 / 추가'\
--header '인증 : XXXXX'

두 필터와 JwtFilter CustomPermissionsAuthorizationFilter 통해이 요청은 사용자 인증 및 권한 부여를 수행한다.

인증 과정은 이것이다 :

. (1)는 AccessControlFilter # onPreHandle ()을
2 AuthenticationFilter isAccessAllowed 번호 ()는,이 방법은 현재 대상 (대상 유저)가 인증되었는지의 여부를 판정 결과가 인증되지 않은 subject.authenticated.
3, # JwtFilter onAccessDenied ()는, 사용자가 인증되지 않고,이 방법은 호출된다.
4 JwtFilter # executeLogin ()에서 승인 요청 헤더 생성 JwtToken를 사용하여, 다음을 수행 subject.login (JwtToken)
. 5, # AuthenticatingRealm getAuthenticationInfo () JwtToken 쿼리 캐시 AuthenticationInfo 의한
. 6 일없이 캐시 AuthenticationInfo 입력 JwtRealm # doGetAuthenticationInfo (), 정당성 체크 토큰 및 SimpleAuthenticationInfo를 생성합니다.

7, 교장 SimpleAuthenticationInfo 사용이 검증 대상을 생성 DefaultWebSubjectFactory # createSubject, 사용자 인증이 완료됩니다.

인증 과정은 이것이다 :

. 1, # AccessControlFilter onPreHandle ()
2 PermissionsAuthorizationFilter isAccessAllowed # (), 피사체의 인터페이스 권한을 포함하는지의 여부를 결정하는 단계를 포함한다.
3, # AuthorizingRealm getAuthorizationInfo ()는 인증 캐시를 얻었다.
(4) 어떤 인증 캐시가인가 정보 JwtRealm # doGetAuthorizationInfo을 얻었다 않음 ().

세션의 사용 테스트 케이스. 다음과 같이 준비 단계는 다음과 같습니다

1, 주석 코드 릴리스의 OpenApiCtrl # openLogin ().

JwtToken jwtToken 새로운 JwtToken을 (토큰) =;
제목 주제는 SecurityUtils.getSubject을 () =;
subject.login (jwtToken);

2, ShiroConfig # 보안 관리자 () 코드 저장 세션을 사용하지 댓글을 달았습니다.

//DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
//DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
//defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
//subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
//manager.setSubjectDAO(subjectDAO);

3, ShiroConfig # shiroFilterFactoryBean (), 권한은 인터페이스 만 사용하는 CustomPermissionsAuthorizationFilter

definitionMap.put ( "/ 사용자 / 추가", "customPerms ["+ userService.getUserAdd () getName () +. "]");
definitionMap.put ( "/ 사용자 / 삭제", "customPerms [". userService.getUserDelete + () getName () + "]")를;
definitionMap.put ( "/ 사용자 / 편집", "customPerms [". userService.getUserEdit + () getName () + "]");
definitionMap.put ( "/ 사용자 /보기", "customPerms ["+ userService.getUserView () getName () +. "]");
definitionMap.put ( "/ 테스트 / 기타", "customPerms [". userService.getTestOther + () getName () + "]")를;
definitionMap.put ( "/ 역할 / 권한 / 편집", "customPerms ["+ userService.getRolePermisssionEdit () getName () +. "]");

시작 프로젝트

도 1에서, 제 1 요구 배달부 로컬 호스트를 사용 : 8080 / 열기 / 로그인

당신이 요청이 아직 성공 찾을 것, 허가없이 8080 / 사용자 /보기,하지만 헤더 : 2, 다음 우편 배달부 요청 로컬 호스트를 사용합니다.

이유는 무엇입니까?

1, PermissionsAuthorizationFilter # isAccessAllowed ()를 발견하고 코드의 라인이 있습니다 

주제 주제의 getSubject (요청, 응답) =;

우리는 당신이 요청은이다를 시작하는 시로 사용자를 아는 방법은, 피사체가, 시로 사용자의 사용자 ID와 주체 될 수 있습니다 이야기?

2, # DefaultWebSubjectFactory createSubject ()이 방법은 다음의 코드를 갖는다

PrincipalCollection 주체 wsc.resolvePrincipals = ();
부울 인증 wsc.resolveAuthenticated = ();

우리는에서 세션에 저장되어있는 원칙 (사용자 ID), 인증 (인증 상태) 시로, 세션을 해제하지 않고, 알 수있는 소스 코드를 디버깅.

8080 / 사용자 / 또는 이유 인증 요청 헤더가 공인 할 수없이 시간에 관계없이 볼 : 요청 로컬 호스트는 이유입니다.

쿠키 경우, 세션의 우편 배달부를 삭제

요청을 다시 로컬 호스트 : 8080 / 사용자 /보기. 디버그 소스
PrincipalCollection 주체 = wsc.resolvePrincipals (); // 교장은 null 인
부울 wsc.resolveAuthenticated 인증 = (); // 인증은 false입니다

CustomPermissionsAuthorizationFilter # onAccessDenied ()가 호출, "불충분 한 권한"정보에 반환.

일반 캐시 지우기

    /**
     * 测试清除jwtRealm缓存
     * MemoryConstrainedCacheManager使用的是Map作为缓存,必须用定时器清理
     */
    @GetMapping("/cache/test")
    public Result test2(){
        Cache<Object, AuthenticationInfo> authen = jwtRealm.getAuthenticationCache();
        Cache<Object, AuthorizationInfo> author = jwtRealm.getAuthorizationCache();
        log.info("当前缓存, 认证缓存 = {} 授权缓存 = {}", authen, author);

        authen.clear();
        author.clear();
        log.info("缓存清除完成,认证缓存size = {} 授权缓存size = {}", authen.size(), author.size());

        return Result.success("test");
    }

수정 권한 구성

    /**
     * 测试动态修改接口授权配置
     */
    @GetMapping("/definition/test")
    public Result test1() throws Exception{

        AbstractShiroFilter shiroFilter = (AbstractShiroFilter)shiroFilterFactoryBean.getObject();
        PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter.getFilterChainResolver();
        DefaultFilterChainManager manager = (DefaultFilterChainManager) filterChainResolver.getFilterChainManager();
        // 清空老的权限控制
        manager.getFilterChains().clear();
        shiroFilterFactoryBean.getFilterChainDefinitionMap().clear();

        // 生成新的definitionMap
        LinkedHashMap<String, String> definitionMap = new LinkedHashMap<>();
        definitionMap.put("/open/**", "anon");

        definitionMap.put("/user/delete", "jwt, customPerms["+userService.getUserDelete().getName()+"]");
        definitionMap.put("/user/edit", "jwt, customPerms["+userService.getUserEdit().getName()+"]");
        definitionMap.put("/user/add", "jwt, customPerms["+userService.getUserAdd().getName()+"]");
        definitionMap.put("/user/view", "jwt, customPerms["+userService.getUserView().getName()+"]");
        definitionMap.put("/test/other", "jwt, customPerms["+userService.getTestOther().getName()+"]");
        definitionMap.put("/role/permission/edit", "jwt, customPerms["+userService.getRolePermisssionEdit().getName()+"]");

        definitionMap.put("/**", "jwt");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(definitionMap);

        // 重新构建生成权限过滤链
        for (Map.Entry<String, String> entry : definitionMap.entrySet()) {
            String url = entry.getKey();
            String chainDefinition = entry.getValue();
            manager.createChain(url, chainDefinition);
        }

        return Result.success("test");
    }

 

게시 51 개 원래 기사 · 원 찬양 14 ·은 40000 +를 볼

추천

출처blog.csdn.net/u010606397/article/details/104110093