精华内容
下载资源
问答
  • #Spring Security简单入门与自定义配置 一、请先学习两个单词 authorization授权 authentication认证 二、Spring Security简介 Spring Security is a powerful and highly customizable authentication and access-...

    #

    Spring Security简单入门与自定义配置

    一、请先学习两个单词

    authorization授权
    authentication认证
    

    二、Spring Security简介

    Spring Security is a powerful and highly customizable authentication and access-control framework. It is the de-facto standard for securing Spring-based applications.

    Spring Security is a framework that focuses on providing both authentication and authorization to Java applications. Like all Spring projects, the real power of Spring Security is found in how easily it can be extended to meet custom requirements
    Spring Security所解决的问题就是安全访问控制,而安全访问控制功能其实就是对所有进入系统的请求进行拦截,校验每个请求是否能够访问它所期望的资源。Spring Security对Web资源的保护是靠Filter实现的。

    三、配置运行环境

    与springboot结合使用,需要额外导入依赖

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    

    四、简单的demo

    这时我们就简单的配置好了运行环境(不要忘记导入web的相关依赖)
    我们启动项目,打开浏览器,访问localhost,发现会自动弹出页面。 springboot进行了自动装配。同时控制台会有输出,当然这个值是随机的

      Using generated security password: dfbed846-28a8-445c-9dbb-badf776d239a
    

    这时我们输入username:root,password为以上即可成功进入

    五、自定义登陆逻辑并授权

    我们需要实现一个接口UserDetailsService,实现其中的方法loadUserByUsername
    示例如下

    @Service // 不要忘记交给spring去管理 
    public class UserDetailServiceImpl implements UserDetailsService {
    
        @Autowired
        private PasswordEncoder passwordEncoder;
    
        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
             // 通常需要在数据库查询,便于演示假定其为admin
            if(!"admin".equals(username)){
                throw new UsernameNotFoundException("用户名不存在");
            }
            String password = passwordEncoder.encode("123");
    
            return new User(username,password,
                    AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
        }
    }
    

    需要注意的是,PasswordEncoder为一个接口,他的实现类的注入需要我们手动去完成,这个类为加密方式,通常采用BCryptPasswordEncoder

    @Bean
    public PasswordEncoder getPw() {
        return new BCryptPasswordEncoder();
    }
    

    以下工具类为用户授权,有两种写法,一种如下直接授予"admin"权限,当然可以自定义(VIP之类的都可),其为List说明可以用逗号分隔赋予多种权限

    AuthorityUtils.commaSeparatedStringToAuthorityList("admin"))
    

    第二种为定义角色,必须用ROLE_定义,如ROLE_root。当然也可以用逗号分隔,进行多角色,多权限定义
    注意返回值UserDetails为接口,我们也可以定义自己的实现类。但此处采用User实现类,注意不要导错包

    六、自定义登录页面

    使用自带的登录页面并不美观,并且难以实现更加个性化的内容。首先准备好自己的login.html的页面,将其表单的参数设置为如下

    <form action="/login" method="post">
        用户名<input type="text" name="username"><br/>
        密码<input type="password" name="password"><br/>
        <input type="submit" value="登录">
    </form>
    

    name的值建议为username和password这样在后面配置的时候就不用手动更改,避免麻烦。同时记住表单提交的action="/login"

    然后增加一个配置类去继承WebSecurityConfigurerAdapter,覆盖其中的configuer(HttpSecurity http)方法
    参考如下

    protected void configure(HttpSecurity http) throws Exception {
            // 表单提交
            http.formLogin()
                    // 自定义登录页面
                    .loginPage("/login.html")
                    // 必须得和login.html中的action一致
                    .loginProcessingUrl("/login");
            // 身份认证
            http.authorizeRequests()
                    .antMatchers("/login.html").permitAll()
                    .anyRequest().authenticated();
            // 关闭csrf防护
            http.csrf().disable();
    }
    

    身份认证部分下面在看
    这时我们按住ctrl键点击loginPage可以看见上一部分的源码

        public FormLoginConfigurer() {
            super(new UsernamePasswordAuthenticationFilter(), (String)null);
            this.usernameParameter("username");
            this.passwordParameter("password");
        }
    

    发现之所以表单提交时要做命名要做这样的规定是因为对于usernameParameter和passwordParameter做了默认规定,所以我们闲得慌的话也可以对这个自定义,在链中写接着写.usernameParameter()就可实现对其的自定义

    七、自定义登陆成功的跳转页面,登录失败的跳转页面

    以成功为例,失败的方法与其相同

    protected void configure(HttpSecurity http) throws Exception {
            // 表单提交
            http.formLogin()
                    // 自定义登录页面
                    .loginPage("/login.html")
                    // 必须得和login.html中的action一致
                    .loginProcessingUrl("/login")
                    .successForwardUrl("/toIndex");
            // 授权
            http.authorizeRequests()
                    .antMatchers("/login.html").permitAll()
                    .anyRequest().authenticated();
            // 关闭csrf防护
            http.csrf().disable();
        }
    

    点进源码看到

    public FormLoginConfigurer<H> successForwardUrl(String forwardUrl) {
            this.successHandler(new ForwardAuthenticationSuccessHandler(forwardUrl));
            return this;
        }
    

    实际上是返回了一个successHandler,并且其中的参数为forwardUrl。说明方式为转发。如果我们想搞点坏的,玩一手重定向到www.baidu.com。采用默认的方法就不行,需要我们自己去重写ForwardAuthenticationSuccessHandler的接口AuthenticationSuccessHandler的实现类

    public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
    
        private String url;
    
        public MyAuthenticationSuccessHandler(String url) {
            this.url = url;
        }
    
        @Override
        public void onAuthenticationSuccess(HttpServletRequest httpServletRequest,
                                            HttpServletResponse httpServletResponse,
                                            Authentication authentication) throws IOException {
            httpServletResponse.sendRedirect(url);
        }
    }
    

    我们采用重定向的方式。这样的话我们直接在链中通过successHandler来书写

    http.formLogin()
                    // 自定义登录页面
                    .loginPage("/login.html")
                    // 必须得和login.html中的action一致
                    .loginProcessingUrl("/login")
                    .successHandler(new MyAuthenticationSuccessHandler("http://www.baidu.com"));
    

    八、身份认证简单分析

    (一)基于代码

    http.authorizeRequests()
        .antMatchers("/login.html").permitAll()
        .anyRequest().authenticated();
    

    authorizeRequests()表示请求授权,默认为拦截所有
    像一些静态资源如css,js,img等不应该被拦截,且登录页面也不应该不拦截

    antMatchers()方法表示ant路径匹配原则,用于匹配需要放行内容
    ? : 匹配一个字符
    * :匹配0个或多个字符
    ** : 匹配0个或多个目录

    如antMatchers("/static/**/*.css")表示匹配static下的css资源
    当然也可以使用正则表达式regexMatchers()方法

    permitAll()表示允许所有。即该资源允许所有的用户访问。这时候可以控制他的权限(身份认证)如
    如:
    1.基于权限访问
    hasAuthority(“admin”),需要有admin权限才允许访问,hasAnyAuthority(“admin”,“root”)需要有admin或root权限才能访问。而权限的赋予在自定义登录逻辑时使用了AuthorityUtils.commaSeparatedStringToAuthorityList(“admin”)赋予
    严格区分大小写
    2.基于角色访问
    hasRole(“abc”),需要改角色为abc才能访问,注意此时不要在前面添加ROLE_,角色的赋予同样在AuthorityUtils.commaSeparatedStringToAuthorityList(“admin”,“ROLE_abc”)中给出
    也同样区分大小写
    3.基于IP地址访问
    hasIpAddress(“127.0.0.1”),注意localhost,127.0.0.1,ipconfig查出来的不能通用。

    这时候点进源码可以看到

    public ExpressionUrlAuthorizationConfigurer<H>.ExpressionInterceptUrlRegistry permitAll() {
                return this.access("permitAll");
            }
    

    这些权限的赋予都是返回的一个access表达式。我们同样可以去实现写个access来书写自己的表达式,没什么意思不演示了

    而最后的,表示其他请求都需要拦截

    .anyRequest().authenticated()
    

    (二)基于注解

    首先在主启动类中开启

    @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
    

    securedEnabled = true表示开启了@Secured。通产写在controller层的方法上,如

    @Secured("ROLE_abc")
    @RequestMapping("/toIndex")
    

    表示需要时abc这个角色才能访问/toIndex这个URL。这里ROLE_可写可不写。同样的严格区分大小写

    prePostEnabled = true表示开启@PreAuthorize,作用同@Secured
    如@PreAuthorize(“hasRole(‘abc’)”) = @Secured(“ROLE_abc”),
    当然也有hasAuthority,如同hasRole的写法。

    九、记住我

    同样的在配置类中添加以下链

    // 记住我
    http.rememberMe()
            // 设置数据源
            .tokenRepository(persistentTokenRepository)
            // 超时时间默认为两周,此处手动设置为60秒便于操作
            .tokenValiditySeconds(60)
            // 自定义登录逻辑
            .userDetailsService(userDetailService);
    

    persistentTokenRepository需要注入
    书写其注入配置

    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
        // 自动建表,第一次启动时开启,第二次启动时注释
        //jdbcTokenRepository.setCreateTableOnStartup(true);
        return jdbcTokenRepository;
    }
    

    这时候要导入数据库相关的驱动jar包,以及在application中去配置相关的数据库配置,并且创建一个名为security的数据库。因为这个功能会在本地自动建表进行持久化保存。
    当然也得在login.html中添加以下代码,同样要注意name的值

    记住我<input type="checkbox" name="remember-me" value="true">
    

    十、异常处理

    异常即所谓权限不够,或身份验证错误,的处理方式。并非账号密码登录错误的跳转页面。比如在上面的登录之后要进行之后的页面跳转时,需要admin权限,却没有就会执行该操作

    http.exceptionHandling()
            .accessDeniedHandler(myAccessDeniedHandler);
    

    要自己实现MyAccessDeniedHandler,当然这里采用spring注入的方式

    @Component
    public class MyAccessDeniedHandler implements AccessDeniedHandler {
        @Override
        public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
            // 设置响应状态403,为权限不足
            httpServletResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);
            // 返回json
            httpServletResponse.setHeader("Content-Type","application/json;charset=utf-8");
            PrintWriter writer = httpServletResponse.getWriter();
            writer.write("{\"status\":\"error\",\"msg\":\"权限不足,请联系管理员\"}");
            writer.flush();
            writer.close();
        }
    }
    

    十一、退出登录

    http.logout()
        .logoutSuccessUrl("/login.html");
    
    <a href="/logout">退出</a>
    

    会清除本地的session等。同样得注意href的值

    十二、csrf

    默认为开启状态
    Cross-site request forgery跨域请求伪造
    csrf是为了保证不是其他第三方网站访问。要求访问是携带参数名为_csrf的值为token(在服务端产生的)的内容。如果token和服务端产生的token匹配成功,则正常访问
    开启后只需要在html中添加

    <input type = "hidden" name="_csrf" value=_csrf.token if=_csrf>
    
    展开全文
  • 首先,Spring Security 到底是用来干嘛的? 再次,Security 是怎么工作的?   最后,我们为什么要用Security。 -------------------------------------------------------------------------- 我先大体上说下...

    首先,Spring Security 到底是用来干嘛的?

    再次,Security 是怎么工作的?

     

    最后,我们为什么要用Security。

    --------------------------------------------------------------------------

    我先大体上说下security的工作流程:

       Spring Security对Web安全性的支持大量地依赖于Servlet过滤器。这些过滤器拦截进入请求,并且在应用程序处理该请求之前进行某些安全处理。 Spring Security提供有若干个过滤器,它们能够拦截Servlet请求,并将这些请求转给认证和访问决策管理器处理,从而增强安全性。根据自己的需要,可以使用表7.4中所列的几个过滤器来保护自己的应用程序。 http://baike.baidu.com/link?url=LhguUpz1g7MnakDzFDFRK9D7n6u6wFffzSbJ7Zkcq3QMDNy741SpXMVGAb4jfz_GAa5J0ORkYvKEGYOD2bIQsa
    对于概念,百度百科上的说很明了。
      在我们访问一个资源的之前,会被AuthenticationProcessingFilter(这个过滤器我们会重写)拦截,然后它会调用securityMetadataSource来获取被访问资源所对应的权限集合,然后调用accessDecisionManager 来确认,我们用户是否有权限访问这个资源。
     
    ---------------------------说了这么多 ,还没见代码。-------------------------------
    每个项目的访问入口都是 web.xml,那我们就看他的代码:
     
    复制代码
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
      <display-name>SpringSecurityDemo</display-name>
      <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
      </welcome-file-list>
      
      <!-- 加载Spring security XML 配置文件
          为什么要配置这个文件?!!!
          因为百度! security是什么?  就是依靠一个特殊的过滤器(DelegatingFilterProxy,他是干嘛的?!),
          依靠他来委托一个在spring上下文的一个bean完成工作。
          而这个Bean,说白了就是一个过滤器。
       -->
      <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
            /WEB-INF/securityConfig.xml
            </param-value>
        </context-param>
        
        
      <!-- Spring 容器监听,这尼玛又是个什么东东? 
          listener. 哦 ,是个监听器啊。
          看看他的源码
          public void contextInitialized(ServletContextEvent event)
        {
            contextLoader = createContextLoader();
            if(contextLoader == null)
                contextLoader = this;
            contextLoader.initWebApplicationContext(event.getServletContext());
        }
            瞅见了么,就特么是来加载上面配置的securityConfig.xml文件
       -->
      <listener>
          <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
      </listener>
      
      <!-- 看吧,这就是看个特殊的过滤器,撒手掌柜了,他到底干什么了,为什么我们要配置他?
          我们来扒开他的皮,瞅一瞅吧,
          //这是他的doFilter方法
           public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
            throws ServletException, IOException
        {
            Filter delegateToUse = null;
            synchronized(delegateMonitor)
            {
                if(_flddelegate == null)   //如果bean为空
                {
                    WebApplicationContext wac = findWebApplicationContext();  //给我拿来配置文件
                    if(wac == null)            //虾米?配置文件为空?!  妈的,给老子抛异常! 你给老子监听的配置吃啦?!
                        throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener registered?");
                    _flddelegate = initDelegate(wac);   //这是什么?猜都出来了,在配置文件里召唤bean(感情配置文件就是人才市场,掌柜的招小工了..)
                }
                delegateToUse = _flddelegate; //小工招用完了,就你啦...可怜,三方呢? 工资了?  你他妈的刚毕业吧....
            }
            invokeDelegate(delegateToUse, request, response, filterChain); //照完小工干嘛去?  干活呗!,给老子干! 干!
        }
        //这是initDeletegate
        protected Filter initDelegate(WebApplicationContext wac)
            throws ServletException
        {
            Filter delegate = (Filter)wac.getBean(getTargetBeanName(), javax/servlet/Filter);
            if(isTargetFilterLifecycle())
                delegate.init(getFilterConfig());
            return delegate;
        }
      
        //这是invokeDelegate
      protected void invokeDelegate(Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain)
            throws ServletException, IOException
        {
            delegate.doFilter(request, response, filterChain);
        }
        
        咦? 不对呀,小工要造反了怎么办?  你无良老板就啥都不干? 
        对,我就是啥都不干? 老子就是这么任性。 老子把你们召唤来,就是给了你们生存的价值
     (DelegatingFilterProxy做的事情是代理Filter的方法,从application context里获得bean。
           这让bean可以获得spring web application context的生命周期支持,使配置较为轻便。)
    你们就知足吧!  唉...初来乍到,谁没有被老板坑过....
       -->
          <filter>
            <filter-name>springSecurityFilterChain</filter-name>
            <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>springSecurityFilterChain</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    </web-app>
    复制代码

    这篇我们要讲刽子手  securityConfig。 为什么要说他是刽子手呢?  因为他是无良掌柜的小工,直接的操盘手......

    复制代码
    <?xml version="1.0" encoding="UTF-8"?>
    <beans:beans xmlns="http://www.springframework.org/schema/security"
        xmlns:beans="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
               http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
               http://www.springframework.org/schema/security
               http://www.springframework.org/schema/security/spring-security-3.0.xsd">
        <http access-denied-page = "/accessDenied.jsp">        <!-- 访问拒绝页面 -->
            <form-login login-page="/login.jsp"/>   <!-- 定义登陆界面 -->
            <intercept-url pattern="/login.jsp" filters="none"/>
            <session-management>
                <concurrency-control max-sessions="1" error-if-maximum-exceeded="true"/>  <!-- 用户最大登录数设置为1 ,超过则引发异常 -->
            </session-management>                  
            <custom-filter ref="myFilter" before="FILTER_SECURITY_INTERCEPTOR"/>  <!-- 自定义FILTER ,FilterSecurityInterceptor 负责授权-->
        </http>
        <!-- myFilter -->
        <beans:bean id = "myFilter" class = "com.qbt.spring.security.MyFilterSecurityInterceptor">
                <beans:property name="authenticationManager" ref ="authenticationManager"></beans:property>  <!-- 登陆验证 ,验证你的用户名密码噼里啪啦-->
                <beans:property name="securityMetadataSource" ref = "securityMetadataSource"></beans:property>  <!-- 资源数据源的定义 ,神马权限对应神马资源 噼里啪啦-->
                 <beans:property name="accessDecisionManager" ref="myAccessDecisionManagerBean"></beans:property>  <!-- 访问决策 有没有权限访问资源 噼里啪啦-->
        </beans:bean>                                                 
        
        <!-- 验证配置,认证管理器,实现UserDetailService接口 -->
        <!-- authenticationManager 可以有多个provider提供信息,我们用myUserDetailService获取信息 -->
        <!-- Spring Security中进行身份验证的是AuthenticationManager接口,ProviderManager是它的一个默认实现,
            但它并不用来处理身份认证,而是委托给配置好的AuthenticationProvider,每个AuthenticationProvider会轮流检查身份认证。
            检查后或者返回Authentication对象或者抛出异常 -->
        <authentication-manager alias="authenticationManager">
            <authentication-provider user-service-ref="myUserDetailService"></authentication-provider>    
        </authentication-manager>
        
        <!-- 获取user数据,可以从数据库中获取用户密码,角色等! -->
        <beans:bean id = "myUserDetailService" class = "com.qbt.spring.security.MyUserDetailService"></beans:bean>
        
        <!-- 访问决策器,决定用户的角色,访问的权限 -->
        <beans:bean id = "myAccessDecisionManagerBean" class = "com.qbt.spring.security.MyAccessDecisionManager"></beans:bean>
        
        <!-- 资源数据源的定义 什么资源对应什么权限,或者什么资源能被什么角色访问-->
        <beans:bean id = "securityMetadataSource" class = "com.qbt.spring.security.MyInvocationSecurityMetadataSource"></beans:bean>
        
    </beans:beans>
    复制代码

     
    展开全文
  • @Bean public static NoOpPasswordEncoder passwordEncoder() { return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance(); }
  • Spring Security资源配置入门讲解

    千次阅读 2014-11-24 14:42:06
    首先web.xml配置     [html] view plain copy < context-param >     < param-name > contextConfigLocation param-name >     < param-value >    classpath:/...
    

    这是我使用的表结构

    表名:RESOURCE 解释:资源表
    备注: 资源表

    RESOURCE(资源表)

    是否主键

    字段名

    字段描述

    数据类型

    长度

    可空

    约束

    缺省值

    备注

    ID

    id

    INT(11)

    11

    TYPE

    类型(URL,METHOD)

    VARCHAR(50)

    50

    VALUE

    URL

    VARCHAR(50)

    50

    MODEL_NAME

    模块名

    VARCHAR(50)

    50

    PARENT_ID

    父模块ID

    VARCHAR(50)

    50

     


    表名:ROLE 解释:角色表
    备注: 角色表

    ROLE(角色表)

    是否主键

    字段名

    字段描述

    数据类型

    长度

    可空

    约束

    缺省值

    备注

    ID

    id

    INT(11)

    11

    NAME

    角色名

    VARCHAR(50)

    50

    DESCRIPTION

    角色描述

    VARCHAR(50)

    50

     


    表名:ROLE_RESOURCE 解释:角色资源表
    备注: 角色资源表

    ROLE_RESOURCE(角色资源表)

    是否主键

    字段名

    字段描述

    数据类型

    长度

    可空

    约束

    缺省值

    备注

    ROLE_ID

    角色ID

    VARCHAR(50)

    50

    RESOURCE_ID

    资源ID

    VARCHAR(50)

    50

     


    表名:USER 解释:用户表
    备注: 用户表

    USER(用户表)

    是否主键

    字段名

    字段描述

    数据类型

    长度

    可空

    约束

    缺省值

    备注

    NAME

    用户名

    VARCHAR(50)

    50

    PASSWORD

    密码

    VARCHAR(50)

    50

    DISABLED

    是否有效

    CHAR(1)

    1

    EMAIL

    邮箱

    VARCHAR(100)

    100

     


    表名:USER_ROLE 解释:用户角色表
    备注: 用户角色表

    USER_ROLE(用户角色表)

    是否主键

    字段名

    字段描述

    数据类型

    长度

    可空

    约束

    缺省值

    备注

    USER_ID

    用户ID

    VARCHAR(50)

    50

    ROLE_ID

    角色ID

    VARCHAR(50)

    50

     

    相关的jar包可到spring官网下载,我使用的是spring security 3.1.3

    下载链接:

    http://repo.springsource.org/libs-release-local/org/springframework/security/spring-security/3.1.3.RELEASE/spring-security-3.1.3.RELEASE-dist.zip

     

    首先web.xml配置

     

     

    1. <context-param>  
    2.         <param-name>contextConfigLocation</param-name>  
    3.         <param-value>  
    4.             classpath:/config/*.xml   
    5.         </param-value>  
    6.     </context-param>  
    7.     <!-- spring监听 -->  
    8.     <listener>  
    9.         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
    10.     </listener>  
    11.     <!-- Spring Security会话控制 -->  
    12.     <listener>  
    13.         <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>  
    14.     </listener>  
    15. <!-- Spring security Filter -->  
    16.     <filter>  
    17.         <filter-name>springSecurityFilterChain</filter-name>  
    18.         <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>  
    19.     </filter>  
    20.     <filter-mapping>  
    21.         <filter-name>springSecurityFilterChain</filter-name>  
    22.         <url-pattern>/*</url-pattern>  
    23.     </filter-mapping>  


    这里主要做了三件事,

    1、加载Spring;

    2、加载Spring Security;

    3、添加Spring Security Session监听器(用于控制登录)

     

    Spring Secirty如下:

    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <beans:beans xmlns="http://www.springframework.org/schema/security"  
    3.     xmlns:beans="http://www.springframework.org/schema/beans"  
    4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    5.     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
    6.                         http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">  
    7.       
    8.     <debug/>  
    9.       
    10.     <global-method-security  pre-post-annotations="enabled" />  
    11.       
    12.     <!-- 此目录下不需要过滤 -->  
    13.     <http pattern="/js/**" security="none"/>  
    14.     <http pattern="/resources/**" security="none"/>  
    15.     <http pattern="/css/**" security="none"/>  
    16.     <http pattern="/dwr/**" security="none"/>  
    17.     <http pattern="/images/**" security="none"/>  
    18.     <http pattern="/login.jsp" security="none"/>  
    19.       
    20.       
    21.       
    22.     <http use-expressions="true">  
    23.         <!-- 非匿名用户就允许访问 -->  
    24.         <intercept-url pattern="/index.jsp" access="isAuthenticated()"/>  
    25.         <form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?error=true"  always-use-default-target="true" default-target-url="/index.jsp" />  
    26.         <logout logout-success-url="/login.jsp"/>  
    27.         <!-- 没有权限访问的页面 -->  
    28.         <access-denied-handler error-page="/403.jsp"/>  
    29.         <session-management></session-management>  
    30.         <remember-me/>  
    31.         <custom-filter ref="myFilter" before="FILTER_SECURITY_INTERCEPTOR"/>  
    32.     </http>  
    33.       
    34.       
    35.       
    36.     <!-- 指定提示信息 -->  
    37.     <beans:bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">  
    38.         <beans:property name="basename" value="classpath:spring-security"></beans:property>  
    39.     </beans:bean>  
    40.       
    41.       
    42.     <authentication-manager alias="myAuthenticationManager">  
    43.         <authentication-provider ref="authenticationProvider">  
    44.         </authentication-provider>  
    45.     </authentication-manager>  
    46.       
    47.     <beans:bean id="authenticationProvider"   
    48.         class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">  
    49.             <beans:property name="userDetailsService" ref="userdetailService" />  
    50.             <!--显示用户错误信息-->  
    51.             <beans:property name="hideUserNotFoundExceptions" value="false" />  
    52.             <beans:property  name="passwordEncoder" ref="md5password"></beans:property >  
    53.     </beans:bean>  
    54.     <!-- 密码加密策略 -->  
    55.     <beans:bean name="md5password" class="org.springframework.security.authentication.encoding.Md5PasswordEncoder"></beans:bean>  
    56.       
    57.     <beans:bean name="userdetailService" class="com.yindejin.system.MyAuthenticationManager">  
    58.         <beans:property name="systemService" ref="systemService"></beans:property>  
    59.     </beans:bean>  
    60.       
    61.     <beans:bean name="myFilter" class="com.yindejin.system.MySecurityFilter">  
    62.         <!-- 用户拥有的权限 -->    
    63.         <beans:property name="authenticationManager" ref="myAuthenticationManager" />    
    64.         <!-- 用户是否拥有所请求资源的权限 -->    
    65.         <beans:property name="accessDecisionManager" ref="myAccessDecisionManager" />    
    66.         <!-- 资源与权限对应关系 -->    
    67.         <beans:property name="securityMetadataSource" ref="mySecurityMetadataSource" />  
    68.     </beans:bean>  
    69.       
    70.       
    71.       
    72.        
    73.     <beans:bean id="myAccessDecisionManager" class="com.yindejin.system.MyAccessDecisionManager"></beans:bean>    
    74.     <beans:bean id="mySecurityMetadataSource" class="com.yindejin.system.MySecurityMetadataSource">    
    75.         <beans:constructor-arg name="systemService" ref="systemService"></beans:constructor-arg>    
    76.     </beans:bean>    
    77.       
    78.       
    79.   
    80. </beans:beans>  

    <custom-filter ref="myFilter" before="FILTER_SECURITY_INTERCEPTOR"/>

    这里的FILTER_SECURITY_INTERCEPTOR是Spring Security过滤器链中默认的Filter,

    他的主要功能是

    1、校验用户名、密码;

    2、初始化时一次性加载所有的资源角色信息

    3、检查用户访问权限

    我们自定义的Filter必须在它之前,由于我们自己的过滤器和默认过滤器功能是一样的,所以就替换掉了原来的过滤器。

    接下来是myFilter几个关键类


     

     


    MySecurityFilter

    1. package com.yindejin.system;  
    2.   
    3. import java.io.IOException;  
    4.   
    5. import javax.servlet.Filter;  
    6. import javax.servlet.FilterChain;  
    7. import javax.servlet.FilterConfig;  
    8. import javax.servlet.ServletException;  
    9. import javax.servlet.ServletRequest;  
    10. import javax.servlet.ServletResponse;  
    11.   
    12. import org.springframework.security.access.SecurityMetadataSource;  
    13. import org.springframework.security.access.intercept.AbstractSecurityInterceptor;  
    14. import org.springframework.security.access.intercept.InterceptorStatusToken;  
    15. import org.springframework.security.web.FilterInvocation;  
    16. import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;  
    17.   
    18. public class MySecurityFilter extends AbstractSecurityInterceptor implements Filter {  
    19.     //与applicationContext-security.xml里的myFilter的属性securityMetadataSource对应,  
    20.     //其他的两个组件,已经在AbstractSecurityInterceptor定义  
    21.     private FilterInvocationSecurityMetadataSource securityMetadataSource;  
    22.   
    23.     @Override  
    24.     public SecurityMetadataSource obtainSecurityMetadataSource() {  
    25.         return this.securityMetadataSource;  
    26.     }  
    27.   
    28.     public void doFilter(ServletRequest request, ServletResponse response,  
    29.             FilterChain chain) throws IOException, ServletException {  
    30.         FilterInvocation fi = new FilterInvocation(request, response, chain);  
    31.         invoke(fi);  
    32.     }  
    33.       
    34.     private void invoke(FilterInvocation fi) throws IOException, ServletException {  
    35.         System.out.println("用户发送请求! ");  
    36.         InterceptorStatusToken token = null;  
    37.         token = super.beforeInvocation(fi);  
    38.         try {  
    39.             fi.getChain().doFilter(fi.getRequest(), fi.getResponse());  
    40.         } finally {  
    41.             super.afterInvocation(token, null);  
    42.         }  
    43.     }  
    44.   
    45.     public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {  
    46.         return securityMetadataSource;  
    47.     }  
    48.   
    49.     public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource securityMetadataSource) {  
    50.         this.securityMetadataSource = securityMetadataSource;  
    51.     }  
    52.       
    53.     public void init(FilterConfig arg0) throws ServletException {  
    54.         // TODO Auto-generated method stub  
    55.     }  
    56.       
    57.     public void destroy() {  
    58.         // TODO Auto-generated method stub  
    59.           
    60.     }  
    61.   
    62.     @Override  
    63.     public Class<? extends Object> getSecureObjectClass() {  
    64.         //下面的MyAccessDecisionManager的supports方面必须放回true,否则会提醒类型错误  
    65.         return FilterInvocation.class;  
    66.     }}  


     

    MySecurityMetadataSource

    1. package com.yindejin.system;  
    2.   
    3.   
    4. import java.util.ArrayList;  
    5. import java.util.Collection;  
    6. import java.util.HashMap;  
    7. import java.util.LinkedHashMap;  
    8. import java.util.List;  
    9. import java.util.Map;  
    10. import java.util.Set;  
    11.   
    12. import javax.servlet.http.HttpServletRequest;  
    13.   
    14. import org.springframework.security.access.ConfigAttribute;  
    15. import org.springframework.security.access.SecurityConfig;  
    16. import org.springframework.security.web.FilterInvocation;  
    17. import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;  
    18. import org.springframework.security.web.util.AntPathRequestMatcher;  
    19. import org.springframework.security.web.util.RequestMatcher;  
    20.   
    21. import com.yindejin.system.service.ISystemService;  
    22. import com.yindejin.vo.Resource;  
    23. import com.yindejin.vo.Role;  
    24. import com.yindejin.vo.User;  
    25.   
    26. //1 加载资源与权限的对应关系  
    27. public class MySecurityMetadataSource implements FilterInvocationSecurityMetadataSource {  
    28.     //由spring调用  
    29.     public MySecurityMetadataSource(ISystemService systemService) {  
    30.         this.systemService = systemService;  
    31.     }  
    32.   
    33.     private ISystemService systemService;  
    34.     public ISystemService getSystemService() {  
    35.         return systemService;  
    36.     }  
    37.   
    38.     public void setSystemService(ISystemService systemService) {  
    39.         this.systemService = systemService;  
    40.     }  
    41.   
    42.     private static LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> resourceMap = null;  
    43.       
    44.   
    45.   
    46.     public Collection<ConfigAttribute> getAllConfigAttributes() {  
    47.         // TODO Auto-generated method stub  
    48.         return null;  
    49.     }  
    50.   
    51.     public boolean supports(Class<?> clazz) {  
    52.         // TODO Auto-generated method stub  
    53.         return true;  
    54.     }  
    55.     //加载所有资源与权限的关系  
    56.     private Map<String, String> getResource() {  
    57.         Map<String, String> resourceMap = new HashMap<String, String>();  
    58.         List<User> users = systemService.getAllUser();  
    59.         for(User user:users){     
    60.             for(Role role : user.getUserRoles()) {  
    61.                 Set<Resource> resources = role.getRoleResources();  
    62.                 for(Resource resource : resources) {  
    63.                         String url = resource.getValue();  
    64.                         if(!resourceMap.containsKey(url)) {  
    65.                             resourceMap.put(url, role.getName());  
    66.                         }else{  
    67.                             String roleName = resourceMap.get(url);  
    68.                             resourceMap.put(url, roleName+","+role.getName());  
    69.                         }  
    70.                 }  
    71.             }  
    72.         }  
    73.         return resourceMap;  
    74.           
    75.     }  
    76.       
    77.     private void loadResourceDefine(){  
    78.         resourceMap = new LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>();  
    79.         Map<String, String> resource = getResource();  
    80.         for(Map.Entry<String, String> entry:resource.entrySet()){  
    81.             Collection<ConfigAttribute> configAttributes = new ArrayList<ConfigAttribute>();  
    82.             configAttributes.add(new SecurityConfig(entry.getValue()));  
    83.             resourceMap.put(new AntPathRequestMatcher(entry.getKey()), configAttributes);  
    84.         }  
    85.           
    86.     }  
    87.       
    88.       
    89.     //返回所请求资源所需要的权限  
    90.     public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {  
    91.           
    92.         HttpServletRequest request = ((FilterInvocation) object).getRequest();  
    93.         if(null==resourceMap){  
    94.             System.out.println("请求地址 " + ((FilterInvocation) object).getRequestUrl());  
    95.             loadResourceDefine();  
    96.             System.out.println("我需要的认证:"+resourceMap.toString());  
    97.         }  
    98.         for (Map.Entry<RequestMatcher, Collection<ConfigAttribute>> entry : resourceMap.entrySet()) {  
    99.             if (entry.getKey().matches(request)) {  
    100.                 return entry.getValue();  
    101.             }  
    102.         }  
    103.         return null;  
    104.     }  
    105.   
    106. }  


    MyAccessDecisionManager

    1. package com.yindejin.system;  
    2.   
    3.   
    4. import java.util.Collection;  
    5. import java.util.Iterator;  
    6.   
    7. import org.springframework.security.access.AccessDecisionManager;  
    8. import org.springframework.security.access.AccessDeniedException;  
    9. import org.springframework.security.access.ConfigAttribute;  
    10. import org.springframework.security.authentication.InsufficientAuthenticationException;  
    11. import org.springframework.security.core.Authentication;  
    12. import org.springframework.security.core.GrantedAuthority;  
    13.   
    14. //3  
    15. public class MyAccessDecisionManager implements AccessDecisionManager {  
    16.       
    17.     public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {  
    18.         if(configAttributes == null) {  
    19.             return;  
    20.         }  
    21.         //所请求的资源拥有的权限(一个资源对多个权限)  
    22.         Iterator<ConfigAttribute> iterator = configAttributes.iterator();  
    23.         while(iterator.hasNext()) {  
    24.             ConfigAttribute configAttribute = iterator.next();  
    25.             //访问所请求资源所需要的权限  
    26.             String needPermission = configAttribute.getAttribute();  
    27.             System.out.println("needPermission is " + needPermission);  
    28.             //用户所拥有的权限authentication  
    29.             for(GrantedAuthority ga : authentication.getAuthorities()) {  
    30.                 if(needPermission.contains((ga.getAuthority()))) {  
    31.                     return;  
    32.                 }  
    33.             }  
    34.         }  
    35.         //没有权限让我们去捕捉  
    36.         throw new AccessDeniedException(" 没有权限访问!");  
    37.     }  
    38.   
    39.     public boolean supports(ConfigAttribute attribute) {  
    40.         // TODO Auto-generated method stub  
    41.         return true;  
    42.     }  
    43.   
    44.     public boolean supports(Class<?> clazz) {  
    45.         // TODO Auto-generated method stub  
    46.         return true;  
    47.     }  
    48.       
    49. }  


     

    MyAuthenticationManager

    1. package com.yindejin.system;  
    2.   
    3. import org.springframework.security.core.userdetails.UserDetails;  
    4. import org.springframework.security.core.userdetails.UserDetailsService;  
    5. import org.springframework.security.core.userdetails.UsernameNotFoundException;  
    6.   
    7. import com.yindejin.system.service.ISystemService;  
    8. import com.yindejin.util.StringUtils;  
    9. import com.yindejin.vo.User;  
    10.   
    11. public class MyAuthenticationManager implements UserDetailsService {  
    12.       
    13.     private ISystemService systemService;  
    14.       
    15.       
    16.     public void setSystemService(ISystemService systemService) {  
    17.         this.systemService = systemService;  
    18.     }  
    19.   
    20.   
    21.     @Override  
    22.     public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {  
    23.         if(!StringUtils.isEmpty(userName)){  
    24.             throw new UsernameNotFoundException("用户名不能为空!");  
    25.         }  
    26.         User user = systemService.loginByUserName(userName);  
    27.         if (user == null) {  
    28.             throw new UsernameNotFoundException("用户名或密码错误!");  
    29.         }  
    30.         return user;  
    31.     }  
    32.   
    33. }  

     

    User

    1. package com.yindejin.vo;  
    2.   
    3. import java.util.ArrayList;  
    4. import java.util.Collection;  
    5. import java.util.HashMap;  
    6. import java.util.HashSet;  
    7. import java.util.List;  
    8. import java.util.Map;  
    9. import java.util.Set;  
    10.   
    11. import javax.persistence.Transient;  
    12.   
    13. import org.springframework.security.core.GrantedAuthority;  
    14. import org.springframework.security.core.authority.GrantedAuthorityImpl;  
    15. import org.springframework.security.core.userdetails.UserDetails;  
    16.   
    17. /** 
    18.  * User entity. @author MyEclipse Persistence Tools 
    19.  */  
    20.   
    21. public class User implements UserDetails {  
    22.   
    23.     // Fields  
    24.   
    25.     private Integer id;  
    26.     private String name;  
    27.     private String password = "123456";  
    28.     private Integer disabled = 0;  
    29.     private String email;  
    30.     public String getEmail() {  
    31.         return email;  
    32.     }  
    33.   
    34.     public void setEmail(String email) {  
    35.         this.email = email;  
    36.     }  
    37.   
    38.     private Set<Role> userRoles = new HashSet<Role>();  
    39.     @Transient  
    40.     private Map<String, List<Resource>> roleResources;  
    41.   
    42.     // Constructors  
    43.   
    44.     public Integer getId() {  
    45.         return id;  
    46.     }  
    47.   
    48.     public void setId(Integer id) {  
    49.         this.id = id;  
    50.     }  
    51.   
    52.     public String getName() {  
    53.         return name;  
    54.     }  
    55.   
    56.     public void setName(String name) {  
    57.         this.name = name;  
    58.     }  
    59.   
    60.     public String getPassword() {  
    61.         return password;  
    62.     }  
    63.   
    64.     public void setPassword(String password) {  
    65.         this.password = password;  
    66.     }  
    67.   
    68.     public Integer getDisabled() {  
    69.         return disabled;  
    70.     }  
    71.   
    72.     public void setDisabled(Integer disabled) {  
    73.         this.disabled = disabled;  
    74.     }  
    75.   
    76.     public Set<Role> getUserRoles() {  
    77.         return userRoles;  
    78.     }  
    79.   
    80.     public void setUserRoles(Set<Role> userRoles) {  
    81.         this.userRoles = userRoles;  
    82.     }  
    83.   
    84.     /** default constructor */  
    85.     public User() {  
    86.     }  
    87.   
    88.   
    89.     public String getUsername() {  
    90.         return name;  
    91.     }  
    92.       
    93.     public boolean isAccountNonExpired() {  
    94.         return true;  
    95.     }  
    96.   
    97.     public boolean isAccountNonLocked() {  
    98.         return true;  
    99.     }  
    100.   
    101.     public boolean isCredentialsNonExpired() {  
    102.         return true;  
    103.     }  
    104.   
    105.     public boolean isEnabled() {  
    106.         return this.disabled==0?true:false;  
    107.     }  
    108.       
    109.     /** 
    110.      * @return the roleResources 
    111.      */  
    112.     public Map<String, List<Resource>> getRoleResources() {  
    113.         // init roleResources for the first time  
    114.         if(this.roleResources == null) {              
    115.             this.roleResources = new HashMap<String, List<Resource>>();  
    116.                   
    117.             for(Role role : this.userRoles) {  
    118.                 String roleName = role.getName();  
    119.                 Set<Resource> resources = role.getRoleResources();  
    120.                 for(Resource resource : resources) {  
    121.                     String key = roleName + "_" + resource.getType();  
    122.                         if(!this.roleResources.containsKey(key)) {  
    123.                             this.roleResources.put(key, new ArrayList<Resource>());  
    124.                     }  
    125.                         this.roleResources.get(key).add(resource);                    
    126.                 }  
    127.             }  
    128.                   
    129.         }  
    130.         return this.roleResources;  
    131.     }  
    132.   
    133.     @SuppressWarnings("deprecation")  
    134.     @Override  
    135.     public Collection<GrantedAuthority> getAuthorities() {  
    136.         Set<GrantedAuthority> authSet = new HashSet<GrantedAuthority>();  
    137.         for(Role role : getUserRoles()){  
    138.             authSet.add(new GrantedAuthorityImpl(role.getName()));  
    139.         }  
    140.         return authSet;  
    141.     }  
    142.   
    143.       
    144.   
    145. }  


     

    展开全文
  • spring security 基础入门(配置详解)

    万次阅读 2015-09-09 17:19:54
    Spring Security 是为Java EE项目提供...支持基于配置文件,JDBC,LADP和自定义的验证方式。能够通过URL路径等途径提供安全服务。本文将介绍通过自定义的验证方式,通过URL拦截来使用springsecurity提供的安全服务。

            Spring Security 是为Java EE项目提供全面安全服务的框架。支持基于配置文件,JDBC,LADP和自定义的验证方式。能够通过URL路径等途径提供安全服务。本文将介绍通过自定义的验证方式,通过URL拦截来使用springsecurity提供的安全服务。


    基本配置

    •  首先导入附件中SpringMVC的最小项目baseSpringMvc
    •  添加依赖项目 spring-security-web和spring-security-config。这里使用spring-security4.0.2.RELEASE 依赖spring的版本为4.1.6。若spring低于该版本maven会再导入一个spring版本,造成冗余。

    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-web</artifactId>
        <version>4.0.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-config</artifactId>
        <version>4.0.2.RELEASE</version>
    </dependency>
    

    •  在web.xml中添加springSecurity的filter。
    <filter>
       <filter-name>springSecurityFilterChain</filter-name>
       <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <filter-mapping>
       <filter-name>springSecurityFilterChain</filter-name>
       <url-pattern>/*</url-pattern>
    </filter-mapping>
    

    • 添加配置文件spring-security.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns:sec="http://www.springframework.org/schema/security"
           xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/security
    http://www.springframework.org/schema/security/spring-security-4.0.xsd">
        <sec:http>
            <!--路径'/admin/*'需要权限ROLE_ADMIN-->
            <sec:intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')"/>
            <!--以"/user"开头的所有路径需要ROLE_USER权限-->
            <sec:intercept-url pattern="/user**" access="hasRole('ROLE_USER')" />
            <!--制定自定义的登录路径为/login,登录后默认跳转/welcome-->
            <sec:form-login login-page="/login" default-target-url="/welcome" />
            <!--指定使用默认登出页面,登出后跳转到/login?logout页面-->
            <sec:logout logout-success-url="/login?logout"/>
            <!--对于没有权限的页面跳转到/403路径-->
            <sec:access-denied-handler error-page="/403" />
            <sec:csrf/>
        </sec:http>
        <sec:authentication-manager>
            <sec:authentication-provider user-service-ref="myUserDetailsService"/>
        </sec:authentication-manager>
        <bean id="myUserDetailsService"
              class="com.springframework.security.userservice.MyUserDetailsService"/>
    </beans>
    
            http段指定了路径相关的配置。

            Intercept-url 段指定路径拦截权限控制的规则,pattern为匹配的路径模式,access是权限检查的表达式,即springSecurity拦截满足pattern的路径请求,当用户权限满足access所指定的表达式时才能继续访问,否则返回403界面。

            form-login段指定login的配置信息。Login-page用于指定自定义的登陆界面路径,default-target-url指定登陆后默认跳转的路径。

            Logou段配置登出时的相关信息。Logout-success-url配置登出之后默认跳转的页面

            Access-denied-handler配置无权访问时的页面配置。error-page指定使用errorpage的方式提示用户无权访问,error-page的参数为一个路径。

            Csrf 用户防止用户伪造表单提交,csrf在表单中使用如下。  

    <input type="hidden"name="${_csrf.parameterName}"
             value="${_csrf.token}"/>

            Authentication-manager 段配置用户验证相关的信息。

            Authentication-provider为authentication provider的配置,这里可以使用user-service-ref属性向其添加一个自定义的userservice用于用户验证,自定义的userservice必须实现UserDetailsService接口。

            Authentication-provider中还有一些springSecurity内置的authentication可以选择,本文就不做详细介绍了。Authentication-provider中jdbc-user-service元素用于基于数据库的验证详细介绍请参考 http://www.mkyong.com/spring-security/spring-security-form-login-using-database/。Authentication-provider中user-service元素用于在配置文件中静态指定用户账户信息。Authentication-provider中ldap-user-service元素用于配置ldap验证。

    •  创建类 com.springframe.security.userservice.MyUserService

    @Component
    public class MyUserDetailsService implements UserDetailsService {
        public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
            ArrayList<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
            authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
            if(s.compareTo("lipore")==0){
                return new User(s,"123456",authorities);
            }else if(s.compareTo("admin")==0){
                authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
                return new User(s,"123456",authorities);
            }
            return null;
        }
    }
    
            MyUserDetailsService 实现UserDetailsService接口。

            LoadUserByUsername在springSecurity进行用户验证的时候掉用来获取一个用户。这里springSecurity提供了一个途径使得开发者可以使用自定义的方式来给spring-Security提供用户信息。通过这个方法我们可以使用数据库,文件等各种形式向springSecurity提供用户用于权限验证。若需要扩展用户信息,请重新实现UserDetails接口。

            SpringSecurity可以使用两种方式来使用数据库。一个方式是在配置中使用jdbc-user-service,另外一个方式是使用自定义userservice 并在自己的loadUserByUsername中获取用户。后者相对于前者来说灵活性更高可以拓展用户信息,但需要做更多的工作。

    • 登录控制器及界面

            这里我们使用自定义的login界面。自定义的登陆界面上我们可以使用验证码,密码加密等。登陆界面表单中必须要元素username和 password,并使用post方式提交到/login路径 (这个路径和我们的控制器无关,springSecurity会自动拦截和跳转)。若启用了csrf别忘了在表单中添加csrf的hiddeninput。登陆界面代码如下。

    RBACController.java

    @Controller
    public class RBACController {
        @RequestMapping(value = "/login",method = RequestMethod.GET)
        public String login(){
            return "login";
        }
    }
    

    login.jsp

    <%--
      Created by IntelliJ IDEA.
      User: Ricky.Gu
      Date: 9/9/2015
      Time: 9:33 AM
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title></title>
    </head>
    <body>
    <form action="/login" method="POST">
      <table>
        <tr>
          <td>User:</td>
          <td><input type='text' name='username'></td>
        </tr>
        <tr>
          <td>Password:</td>
          <td><input type='password' name='password' /></td>
        </tr>
        <tr>
          <td colspan='2'><input name="submit" type="submit"
                                 value="submit" /></td>
        </tr>
      </table>
    
      <input type="hidden" name="${_csrf.parameterName}"
             value="${_csrf.token}" />
    
    </form>
    </form>
    </body>
    </html>
    
    • 权限控制测试

            Spring-security.xml配置文件中我们指定了两拦截器:一个用于拦截/admin/**需要ROLE_ADMIN权限访问;另外一个用于拦截/user*需要ROLE_USER权限访问。除了两个拦截器拦截的路径外其他路径不需要权限即可访问。

            /welcome 不需要权限即可访问,我们在里面测试下获取用户名。

            /user需要ROLE_USER权限

            /admin/info需要ROLE_ADMIN权限

    CommonController.java
    @Controller public class CommonController {
        @RequestMapping("/welcome")
        public String welcome(Model model) {
            Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
            String username = principal instanceof String ?
                    (String) principal :
                    (principal instanceof UserDetails ? ((UserDetails) principal).getUsername() : "");
            model.addAttribute("username",username);
            return "welcome";
        }
    
        @RequestMapping("/user")
        @ResponseBody
        public String userInfo() {
            return "you have user role";
        }
    
        @RequestMapping("/admin/info")
        @ResponseBody
        public String info(){
            return "you have role admin";
        }
    }
    

    Welcome.jsp

    <%--
      Created by IntelliJ IDEA.
      User: rgu
      Date: 9/9/2015
      Time: 10:02 AM
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title></title>
    </head>
    <body>
    <script>
      function formSubmit() {
        document.getElementById("logoutForm").submit();
      }
    </script>
    <form id="logoutForm" action="/logout" method="post">
      <input type="hidden" name="${_csrf.parameterName}"
             value="${_csrf.token}" />
    </form>
      welcome:${username}|<a href="javascript:formSubmit()"> Logout</a>
    </body>
    </html>
    

    *welcome.jsp中的表单用于测试登出操作。


    展开全文
  • 文章目录安全框架之SpringSecurity入门到精通 安全框架之SpringSecurity入门到精通
  • 学习项目中用到了Spring ...首先贴上全部spring security配置文件代码,还是一样,因为我这个是maven项目,所以需要提前在pom文件里写好依赖,以下pom文件内容仅供参考 <properties> <spring.version>...
  • 此处使用spring Security...配置文件:spring-security.xml &lt;beans xmlns="http://www.springframework.org/schema/beans" xmlns:security="http://www.springframework.org/schema/securi...
  • Spring Security 快速入门

    千次阅读 2019-04-22 14:35:48
    Spring Security是一个强大的、支持深度定制的安全控制框架,他为Java应用提供了认证(Authentication)和授权(Authorization)功能,使得开发者...本次快速入门分成两个部分:自定义UserDetailsService和自定义Authe...
  • 上一篇文章《Spring Security(二)—Guides》,通过Spring Security配置项了解了Spring Security是如何保护我们的应用的,...这是Spring Security入门指南中的配置项: @Configuration @EnableWebSecurity public...
  • springSecurity使用入门

    2020-06-12 15:49:05
    二.springSecurity入门项目 1.使用maven创建一个javaweb项目 2.在main下新建一个目录 并标记为资源目录 3.配置pom.xml 导入依赖 <properties> <spring.version>5.0.2.
  • Deep Security 8入门安装指南 趋势防毒墙
  • 这篇文章主要介绍了SpringBoot + Spring Security 简单入门 Spring Security 基本介绍 这里就不对Spring Security进行过多的介绍了,具体的可以参考官方文档 我就只说下SpringSecurity核心功能: 认证(你是谁)...
  • spring security简单使用初识spring security入门案例简介项目结构测试编写Spring Security配置类测试 初识spring security Spring Security 是针对Spring项目的安全框架,也是Spring Boot底层安全模块默认的技术...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 24,322
精华内容 9,728
关键字:

security配置入门