美文网首页Java Web 核心技术
spring boot 整合 spring security4

spring boot 整合 spring security4

作者: PrimaryKeyEnoch | 来源:发表于2017-02-06 13:11 被阅读4645次

    我们在编写Web应用时,经常需要对页面做一些安全控制,比如:对于没有访问权限的用户需要转到登录表单页面。要实现访问控制的方法多种多样,可以通过Aop、拦截器实现,也可以通过框架实现(如:Apache Shiro、Spring Security)。

    本文将具体介绍在Spring Boot中如何使用Spring Security进行安全控制。
    整体框架: spring boot spring data jpa spring security

    心得

    在整理当前框架时,遇到了几个问题

    <sec:authorize access="hasRole('ROLE_USER')">
         这里是角色ROLE_USER可以看到
    </sec:authorize> 
    <sec:authorize url="/admin">
       这里是具有 /admin 资源的用户可以看到
    </sec:authorize>
    

    当时官网是这样描述着两个标签的
    此标记用于确定是否应评估其内容。在spring 3.0,它可以以两种方式使用 。第一种方法使用了网络的安全性表达,在指定access标签的属性。表达式求值将被委托给SecurityExpressionHandler<FilterInvocation>应用程序上下文中定义(你应该在你的基于Web的表达<http>空间配置,以确保该服务可用)。所以,例如,你可能有<sec:authorize access="hasRole('ROLE_USER')"></sec:authorize>这这种标签可以直接使用 .
    但是对于 URL 来讲就没那么简单了.需要自定义DefaultWebInvocationPrivilegeEvaluator类. 下面我会给出详细设计代码,在这之前我想多说一句,当时扩展的时候我遇到了标签不起作用,百度 谷歌了好久,也没有解决问题.我在群里问人的时候,群里的回答也是让我大写的服...一个个的都不认字吗?
    有人回答说用 shiro 吧....有人回答说,谁还用 JSP... 有人回答说,自定义标签吧...有人回答说,用 hasrole 标签吧... url 没用....我真是服了,,我求求你们,你们是怎么当上程序员的啊!!!!!当别人问你们问题的时候,,你们的回答也是大写的服!!!!!! 别人用 jsp 咋了,,跟当前问的问题有任何关系吗?所以啊有什么问题还是靠自己解决啊.. 于是就跟踪源代码DefaultWebInvocationPrivilegeEvaluator. java中有个securityInterceptor属性.这个属性就决定是用扩展自定义的类还是用 springsecurity 本身自己的类...最后发现是我这个地方没有注入进去..查询了官方 API, 原来发现 javaconfig 的方式在在

     public void configure(WebSecurity web) throws Exception {
           web.securityInterceptor(myFilterSecurityInterceptor);
           web.privilegeEvaluator(customWebInvocationPrivilegeEvaluator());
    }
    

    这样才能做到注入自己的扩展的FilterSecurityInterceptor,下面我会给出详细代码.
    参考文档 http://docs.spring.io/spring-security/site/docs/4.2.2.BUILD-SNAPSHOT/reference/htmlsingle/
    http://docs.spring.io/spring-security/site/docs/current/apidocs/org/springframework/security/config/annotation/web/builders/WebSecurity.html
    解决问题还是得靠自己. 多看文档,多跟踪源代码,多看 API. 下面开始进入正题.

    表设计

    springsecurity框架的表设计还是很简单的, user 用户表, role 角色表, resource 资源表.然后三者通过关系关联,我这里设计了5张表, user,role,resource,user_role,role_resource 其中user_role表是用户与角色之间的关系,多对多,role_resource 关系也是这样.

    实体类

    user.java
    
    @Entity
    @Table(name = "ad_operator_info")
    public class User extends BaseEntity {
       /**
        * 主键
        */
       @Id
       @GeneratedValue(generator = "uuid")
       @GenericGenerator(name = "uuid", strategy = "uuid")
       @Column(name = "oper_id", length = 32)
       private String operId;
       /**
        * 用户名
        */
       @Column(name = "user_name")
       private String userName;
       /**
        * 密码
        */
       private String password;
    
       @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
       @JoinTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
       private Set<Role> roles;
    
       //省略 get... set..
    }
    
    role.java
    
    @Entity
    @Table(name = "ad_role")
    public class Role extends BaseEntity {
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        private String name;
    
        @ManyToMany(mappedBy = "roles", fetch = FetchType.LAZY)
        private Set<OperatorInfo> users;
    
        @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
        @JoinTable(name = "ad_roles_resources", joinColumns = {@JoinColumn(name = "rid")}, inverseJoinColumns = {@JoinColumn(name = "eid")})
        private Set<Resource> resources;
       // 省略 get set
    }
    
    Resource.java
    
    @Entity
    @Table(name = "ad_web_resource")
    public class WebResource extends BaseEntity {
    
        private static final long serialVersionUID = 7926081201477024763L;
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id; // 主键
    
        private String name; // 资源名称
    
        private String url;
    
        @Column(name="remark",length=200)
        private String remark;//备注
    
        @Column(name="methodName",length=400)
        private String methodName;//资源所对应的方法名
    
        @Column(name="methodPath",length=1000)
        private String methodPath;//资源所对应的包路径
    
        private String sn;
    
        private String value; // 资源标识
       
       // 省略 get set  这里的属性可以根据自己的业务来.
    }
    

    实体类就此准备完毕. 下面加入 springsecurity 的 jar 包

    1. 下载 jar
    <parent>  
            <groupId>org.springframework.boot</groupId>  
            <artifactId>spring-boot-starter-parent</artifactId>  
            <version>1.4.1.RELEASE</version>  
        </parent>  
        <dependencies>  
            <dependency>  
                <groupId>org.springframework.boot</groupId>  
                <artifactId>spring-boot-starter-web</artifactId>  
            </dependency>  
            <dependency>  
                <groupId>org.springframework.boot</groupId>  
                <artifactId>spring-boot-starter-security</artifactId>  
            </dependency>  
            <dependency>
                <groupId>org.springframework.security</groupId>
                <artifactId>spring-security-taglibs</artifactId>
                <version>4.2.1.RELEASE</version>
            </dependency>
    </dependencies>  
    

    2 .Spring Security配置
    创建Spring Security的配置类 WebSecurityConfig,也是注入自己定义扩展FilterSecurityInterceptor的重要类 ,具体如下:

    import com.pwkj.potevio.adp.auth.MyFilterSecurityInterceptor;
    import com.pwkj.potevio.adp.auth.MyUserDetailService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.builders.WebSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
    /**
     * Created by PrimaryKey on 17/2/4.
     *
     * @EnableWebSecurity: 禁用Boot的默认Security配置,配合@Configuration启用自定义配置(需要扩展WebSecurityConfigurerAdapter)
     * @EnableGlobalMethodSecurity(prePostEnabled = true): 启用Security注解,例如最常用的@PreAuthorize
     * configure(HttpSecurity): Request层面的配置,对应XML Configuration中的<http>元素
     * configure(WebSecurity): Web层面的配置,一般用来配置无需安全检查的路径
     * configure(AuthenticationManagerBuilder): 身份验证配置,用于注入自定义身份验证Bean和密码校验规则
     */
    
    
    @Configuration
    @EnableWebSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Autowired
        private MyUserDetailService myUserDetailService;
        @Autowired
        private MyFilterSecurityInterceptor myFilterSecurityInterceptor;
    
       @Bean
        @Primary
        public DefaultWebInvocationPrivilegeEvaluator customWebInvocationPrivilegeEvaluator() {
            return new DefaultWebInvocationPrivilegeEvaluator(myFilterSecurityInterceptor);
        }
        @Bean
        public BCryptPasswordEncoder bCryptPasswordEncoder() {
            return new BCryptPasswordEncoder();
        }
    
        @Override
        public void configure(WebSecurity web) throws Exception {
            // javaconfig 配置是这样 set 进去的.
            web.securityInterceptor(myFilterSecurityInterceptor);
            web.privilegeEvaluator(customWebInvocationPrivilegeEvaluator());
            web.
                    ignoring()
                    .antMatchers("/assets/**", "/login", "/login/success", "/kaptcha/**", "/**/*.jsp");
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().disable()
                    .authorizeRequests()
                    .antMatchers("/resources", "/login", "/kaptcha/**").permitAll()//访问:这些路径 无需登录认证权限
                    .anyRequest().authenticated() //其他所有资源都需要认证,登陆后访问
                    //.antMatchers("/resources").hasAuthority("ADMIN") //登陆后之后拥有“ADMIN”权限才可以访问/hello方法,否则系统会出现“403”权限不足的提示
             .and()
                    .formLogin()
                    .loginPage("/")//指定登录页是”/”
                    .permitAll()
                    .successHandler(loginSuccessHandler()) //登录成功后可使用loginSuccessHandler()存储用户信息,可选。
             .and()
                    .logout()
                    .logoutUrl("/admin/logout")
                    .logoutSuccessUrl("/") //退出登录后的默认网址是”/home”
                    .permitAll()
                    .invalidateHttpSession(true);
                   // .and()
                    //.rememberMe()//登录后记住用户,下次自动登录,数据库中必须存在名为persistent_logins的表
                    //.tokenValiditySeconds(1209600);
            http.addFilterBefore(myFilterSecurityInterceptor, FilterSecurityInterceptor.class);
    
        }
    
        @Autowired
        public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
            //指定密码加密所使用的加密器为passwordEncoder()
            //需要将密码加密后写入数据库
            auth.userDetailsService(myUserDetailService);//.passwordEncoder(bCryptPasswordEncoder());
        }
    
        @Bean
        public BCryptPasswordEncoder passwordEncoder() {
            return new BCryptPasswordEncoder(4);
        }
    
        @Bean
        public LoginSuccessHandler loginSuccessHandler() {
            return new LoginSuccessHandler();
        }
    }
    

    编写LoginSuccessHandler.java 此类是在登陆成功之后做一些业务操作

    package com.pwkj.potevio.adp.config;
    
    import com.pwkj.potevio.adp.entity.OperatorInfo;
    import org.springframework.security.core.Authentication;
    import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    /**
     * Created by PrimaryKey on 17/2/4.
     */
    public class LoginSuccessHandler extends
            SavedRequestAwareAuthenticationSuccessHandler {
    
        @Override
        public void onAuthenticationSuccess(HttpServletRequest request,
                                            HttpServletResponse response, Authentication authentication) throws IOException,
                ServletException {
            //获得授权后可得到用户信息   可使用OperatorInfoService进行数据库操作
            OperatorInfo userDetails = (OperatorInfo) authentication.getPrincipal();
           /* Set<SysRole> roles = userDetails.getSysRoles();*/
            //输出登录提示信息
            System.out.println("管理员 " + userDetails.getName() + " 登录");
    
            System.out.println("IP :" + getIpAddress(request));
    
            super.onAuthenticationSuccess(request, response, authentication);
        }
    
    
        public String getIpAddress(HttpServletRequest request) {
            String ip = request.getHeader("x-forwarded-for");
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("Proxy-Client-IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("WL-Proxy-Client-IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_CLIENT_IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_X_FORWARDED_FOR");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
            }
            return ip;
        }
    }
    
    

    下面是自定义的过滤器,也是最重要的集成代码.
    首先编写 MyInvocationSecurityMetadataSource.java 此类是首先加载的,用于加载资源配置.用resourceMap对象存储url --> value

    package com.pwkj.potevio.adp.auth;
    
    /**
     * Created by PrimaryKey on 17/2/4.
     */
    
    import com.pwkj.potevio.adp.dao.WebResourceDao;
    import com.pwkj.potevio.adp.entity.WebResource;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.access.ConfigAttribute;
    import org.springframework.security.access.SecurityConfig;
    import org.springframework.security.web.FilterInvocation;
    import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.PostConstruct;
    import java.util.*;
    
    @Service
    public class MyInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
    
        private static Map<String, Collection<ConfigAttribute>> resourceMap = null;
        private org.slf4j.Logger LOG = LoggerFactory.getLogger(getClass());
    
        @Autowired
        private WebResourceDao webResourceDao;
    
        /**
         * 加载资源,初始化资源变量
         */
        @PostConstruct
        public void loadResourceDefine() {
            if (resourceMap == null) {
                resourceMap = new HashMap<String, Collection<ConfigAttribute>>();
                List<WebResource> resources = webResourceDao.findAll();
                for (WebResource resource : resources) {
                    Collection<ConfigAttribute> configAttributes = new ArrayList<ConfigAttribute>();
                    ConfigAttribute configAttribute = new SecurityConfig(resource.getValue());
                    configAttributes.add(configAttribute);
                    resourceMap.put(resource.getUrl(), configAttributes);
                }
            }
            LOG.info("security info load success!!");
        }
    
        @Override
        public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
            if (resourceMap == null) loadResourceDefine();
            String requestUrl = ((FilterInvocation) object).getRequestUrl();
           // 返回当前 url  所需要的权限
             return resourceMap.get(requestUrl);
        }
    
    
    
        @Override
        public Collection<ConfigAttribute> getAllConfigAttributes() {
            return null;
        }
    
        @Override
        public boolean supports(Class<?> aClass) {
            return true;
        }
    }
    

    其次编写 MyUserDetailService.java 此类用来获取用户的所有权限.

    package com.pwkj.potevio.adp.auth;
    
    import com.pwkj.potevio.adp.entity.OperatorInfo;
    import com.pwkj.potevio.adp.entity.Role;
    import com.pwkj.potevio.adp.entity.WebResource;
    import com.pwkj.potevio.adp.service.OperatorInfoService;
    import com.pwkj.potevio.adp.service.WebResourceService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.authority.SimpleGrantedAuthority;
    import org.springframework.security.core.userdetails.User;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.core.userdetails.UsernameNotFoundException;
    import org.springframework.stereotype.Service;
    
    import java.util.*;
    
    /**
     * Created by PrimaryKey on 17/2/4.
     * 二
     */
    @Service
    public class MyUserDetailService implements UserDetailsService {
    
        @Autowired
        private OperatorInfoService operatorInfoService;
    
        @Autowired
        private WebResourceService webResourceService;
    
        @Override
        public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
            //取得用户
            OperatorInfo operatorInfo = operatorInfoService.findByUserName(userName);
            if (operatorInfo == null) {
                throw new UsernameNotFoundException("UserName " + userName + " not found");
            }
            // 取得用户的权限
            Collection<GrantedAuthority> grantedAuths = obtionGrantedAuthorities(operatorInfo);
            Set<GrantedAuthority> grantedAuthorities = new HashSet<GrantedAuthority>();
            for (Role role : operatorInfo.getRoles()) {
                grantedAuthorities.add(new SimpleGrantedAuthority(role.getName()));
            }
            // 封装成spring security的user
            User userDetail = new User(operatorInfo.getUserName(), operatorInfo.getPassword(),
                    true,//是否可用
                    true,//是否过期
                    true,//证书不过期为true
                    true,//账户未锁定为true ,
                    grantedAuths);
            return userDetail;
        }
    
        // 取得用户的权限
        private Set<GrantedAuthority> obtionGrantedAuthorities(OperatorInfo operatorInfo) {
            List<WebResource> resources = new ArrayList<WebResource>();
            //获取用户的角色
            Set<Role> roles = operatorInfo.getRoles();
            for (Role role : roles) {
                Set<WebResource> res = role.getResources();
                for (WebResource resource : res) {
                    resources.add(resource);
                }
            }
            Set<GrantedAuthority> authSet = new HashSet<GrantedAuthority>();
            for (WebResource r : resources) {
                //用户可以访问的资源名称(或者说用户所拥有的权限)
                authSet.add(new SimpleGrantedAuthority(r.getValue()));
            }
            return authSet;
        }
    }
    ```
    再次编写 ```MyFilterSecurityInterceptor.java``` 用于跳转
    ```
    package com.pwkj.potevio.adp.auth;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.access.SecurityMetadataSource;
    import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
    import org.springframework.security.access.intercept.InterceptorStatusToken;
    import org.springframework.security.web.FilterInvocation;
    import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
    import org.springframework.stereotype.Service;
    
    import javax.servlet.*;
    import java.io.IOException;
    
    /**
     * Created by PrimaryKey on 17/2/4.
     *
     * 三
     */
    @Service
    public class MyFilterSecurityInterceptor extends FilterSecurityInterceptor implements Filter {
    
        @Autowired
        private FilterInvocationSecurityMetadataSource securityMetadataSource;
    
        @Autowired
        public void setMyAccessDecisionManager(MyAccessDecisionManager myAccessDecisionManager) {
            super.setAccessDecisionManager(myAccessDecisionManager);
        }
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
    
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            FilterInvocation fi = new FilterInvocation(servletRequest, servletResponse, filterChain);
            invoke(fi);
        }
    
        public void invoke(FilterInvocation fi) throws IOException, ServletException {
            //fi里面有一个被拦截的url
            //里面调用MyInvocationSecurityMetadataSource的getAttributes(Object object)这个方法获取fi对应的所有权限
            //再调用MyAccessDecisionManager的decide方法来校验用户的权限是否足够
            InterceptorStatusToken token = super.beforeInvocation(fi);
            try {
                //执行下一个拦截器
                fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
            } finally {
                super.afterInvocation(token, null);
            }
        }
    
        @Override
        public void destroy() {
    
        }
    
        @Override
        public Class<?> getSecureObjectClass() {
            return FilterInvocation.class;
        }
    
        @Override
        public SecurityMetadataSource obtainSecurityMetadataSource() {
            return this.securityMetadataSource;
        }
    }
    
    ```
    最后编写```MyAccessDecisionManager.java``` 类用来判断当前用户是否有访问权限.
    ```
    package com.pwkj.potevio.adp.auth;
    
    import org.springframework.security.access.AccessDecisionManager;
    import org.springframework.security.access.AccessDeniedException;
    import org.springframework.security.access.ConfigAttribute;
    import org.springframework.security.authentication.InsufficientAuthenticationException;
    import org.springframework.security.core.Authentication;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.stereotype.Service;
    
    import java.util.Collection;
    import java.util.Iterator;
    
    /**
     * Created by PrimaryKey on 17/2/4.
     *
     * 最后一个类
     */
    @Service
    public class MyAccessDecisionManager implements AccessDecisionManager {
        @Override
        public void decide(Authentication authentication, Object o, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
    
    
            // TODO  权限 .... >>>
            if (configAttributes == null) {
                return;
            }
            //所请求的资源拥有的权限(一个资源对多个权限)
            Iterator<ConfigAttribute> iterator = configAttributes.iterator();
            while (iterator.hasNext()) {
                ConfigAttribute configAttribute = iterator.next();
                //访问所请求资源所需要的权限
                String needPermission = configAttribute.getAttribute();
                 //用户所拥有的权限authentication
                for (GrantedAuthority ga : authentication.getAuthorities()) {
                    System.out.println("-----------PrimaryKey-----------ga.getAuthority()值=" + ga.getAuthority() + "," + "当前类=MyAccessDecisionManager.decide()");
                    if (needPermission.equals(ga.getAuthority())) {
                        return;
                    }
                }
            }
            throw new AccessDeniedException("没有权限访问!");
        }
    
        @Override
        public boolean supports(ConfigAttribute configAttribute) {
            return true;
        }
    
        @Override
        public boolean supports(Class<?> aClass) {
            return true;
        }
    }
    
    ```
     
    
    到此java 代码就已经完成编写了. 然后抓紧时间写个```LoginController``` 吧
    
    ```
        @PostMapping("/login")
        public String login(String userName, String password,Model model) {
            HttpSession session = request.getSession();
            User user = userService.findByUserName(userName);
            if (!passwordEncoder.matches(password, user.getPassword())) {
                 model.addAttribute("error", "用户名或密码错误");
                return "/pages/login";
            }
            // 这句代码会自动执行咱们自定义的 ```MyUserDetailService.java``` 类
            Authentication authentication = myAuthenticationManager.authenticate(new UsernamePasswordAuthenticationToken(userName, password));
            if (!authentication.isAuthenticated()) {
                throw new BadCredentialsException("Unknown username or password");
            }
            SecurityContext securityContext = SecurityContextHolder.getContext();
            securityContext.setAuthentication(authentication);
            session.setAttribute("SPRING_SECURITY_CONTEXT", SecurityContextHolder.getContext());
            session.setAttribute(PlatformConstant.SESSION_OPERATOR, user);
             operateLogService.saveOperateLog(user, request.getRemoteAddr());
            return "index";
        }
    ```
    页面如下
    ```login.jsp```
    ```
    <form action="/user/login"method="POST">
    <table>
        <tr>
            <td>username:</td>
            <td><input type='text'name='username'></td>
        </tr>
        <tr>
            <td>password:</td>
            <td><input type='password'name='password'></td>
        </tr>
        <tr>
            <td><input name="reset"type="reset"></td>
            <td><input name="submit"type="submit"></td>
        </tr>
    </table>
    </form>
    ```
    登陆之后跳转到 index.jsp 
    ```
    这是首页,欢迎<sec:authentication property="name"/>!<br>
    
    <sec:authentication property="authorities"/>  <br/>
    
    <a href="admin.jsp">进入admin页面</a>
    
    <sec:authorize url='/other1.jsp' >
        <a href="other1.jsp">权限1</a>
    </sec:authorize> 
    
    <sec:authorize url='/other2.jsp' >
    <a href="other2.jsp">权限2</a>
    </sec:authorize>
    
    <sec:authorize url='/other3.jsp' >
        <a href="other3.jsp">权限3</a>
    </sec:authorize> 
    ```
    到此,整个标签库都会生效了,,,由于时间有限,,写的有点仓促了,哪里不懂的可以问我.小伙伴抓紧时间试试吧...

    相关文章

      网友评论

      • 行走在爱与恨之间:myAuthenticationManager 这个是在哪里配置的?
        PrimaryKeyEnoch:@行走在爱与恨之间 @autowired
        private AuthenticationManager myAuthenticationManager; 注入一下.
      • 韶光asheng:您好, 你能把数据表结构发出来一下吗?
        PrimaryKeyEnoch:JPA自动生成表呢.
      • waiterchong12:大神问一下 DefaultWebInvocationPrivilegeEvaluator 的自定义类在哪里写的啊
        PrimaryKeyEnoch:@Bean
        @primary
        public DefaultWebInvocationPrivilegeEvaluator customWebInvocationPrivilegeEvaluator() {
        return new DefaultWebInvocationPrivilegeEvaluator(myFilterSecurityInterceptor);
        } 不好意思这个忘记写了..现在改正过来了.
      • 3dff56de5300:http.authorizeRequests().anyRequest().authenticated().withObjectPostProcessor(objectPostProcessor); withObjectPostProcessor 这个方法是干啥的?
      • loths:rest api的权限如何控制?
        PrimaryKeyEnoch:可以通过 hasrole 标签,判断角色,,也可以通过 url 标签,判断是否有当前路径的访问权限.
      • 3a30641fb755:没有看懂 MyFilterSecurityInterceptor 这个类是干啥的?
        PrimaryKeyEnoch: 核心的InterceptorStatusToken token = super.beforeInvocation(fi);会调用我们定义的accessDecisionManager:decide(Object object)和securityMetadataSource
        :getAttributes(Object object)方法。 自己实现的过滤用户请求类,也可以直接使用 FilterSecurityInterceptor
        AbstractSecurityInterceptor有三个派生类: FilterSecurityInterceptor,负责处理FilterInvocation,实现对URL资源的拦截。 MethodSecurityInterceptor,负责处理MethodInvocation,实现对方法调用的拦截。 AspectJSecurityInterceptor,负责处理JoinPoint,主要是用于对切面方法(AOP)调用的拦截。 还可以直接使用注解对Action方法进行拦截,例如在方法上加:@PreAuthorize("hasRole('ROLE_SUPER')")
        private void invoke(FilterInvocation fi) throws IOException, ServletException{}
        // object为FilterInvocation对象
        //super.beforeInvocation(fi);源码
        //1.获取请求资源的权限
        //执行Collection<ConfigAttribute> attributes = SecurityMetadataSource.getAttributes(object);
        //2.是否拥有权限
        //this.accessDecisionManager.decide(authenticated, object, attributes);

      • 疯狂de追梦:@PreAuthorize("ROLE_USER") 这个是在方法执行之前判断是否有user权限,@PostAuthorize("ROLE_USER")这个是在方法执行之后判断是否有权限吗?
        方法都执行了,还需要判断权限吗?
        PrimaryKeyEnoch:您看下这篇帖子对您有帮助没? 讲的很清楚了呢
        http://www.yiibai.com/spring-security/spring-security-4-method-security-using-preauthorize-postauthorize-secured-el.html

      本文标题:spring boot 整合 spring security4

      本文链接:https://www.haomeiwen.com/subject/huoyittx.html