Spring Security之快速入门

生活中,最使人疲惫的往往不是道路的遥远,而是心中的郁闷;最使人痛苦的往往不是生活的不幸,而是希望的破灭;最使人颓废的往往不是前途的坎坷,而是自信的丧失;最使人绝望的往往不是挫折的打击,而是心灵的死亡。所以我们要有自己的梦想,让梦想的星光指引着我们走出落漠,走出惆怅,带着我们走进自己的理想。

导读:本篇文章讲解 Spring Security之快速入门,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

一、Spring Security概述

Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作

二、基于配置使用Spring Security

添加依赖

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

web.xml配置filter

  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring-security.xml</param-value>
  </context-param>
   <!--Spring监听-->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
   <!--Spring Security过滤器-->
  <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的配置

1.使用spring-security.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:security="http://www.springframework.org/schema/security"
       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.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">

	  <!--页面拦截规则-->
    <security:http auto-config="true" use-expressions="false">
    
        <!-- intercept-url 表示拦截页面,定义一个过滤规则
        
        pattern:对哪些url进行权限控制
		        /* 表示的是该目录下的资源,只包括本级目录不包括下级目录
		        /** 表示的是该目录以及该目录下所有级别子目录的资源
		        
        access:请求对应的URL时需要什么权限,是一个以逗号分隔的角色列表,请求的用户只需拥有其中的一个角色就能成功访问对应的URL -->
        <security:intercept-url pattern="/**" access="ROLE_USER" />
        
        <!-- auto-config配置后,不需要在配置下面信息 
        <security:form-login /> form-login开启表单登陆,定义登录表单信息
        <security:http-basic/> 
        <security:logout /> -->
    </security:http>
    
    <!--认证管理器-->
    <security:authentication-manager>
        <security:authentication-provider>
         <!--在内存中存入用户名和密码-->
            <security:user-service>
             <!--{noop}是制定密码加密策略为不加密 。noop的意思是明文保存的密码 (noop: No Operation)-->
                <security:user name="user" password="{noop}user"
                               authorities="ROLE_USER" />
                <security:user name="admin" password="{noop}admin"
                               authorities="ROLE_ADMIN" />
            </security:user-service>
        </security:authentication-provider>
    </security:authentication-manager>
</beans>

制定加密策略为bcrypt

            <security:user-service>
            <!--修改配置文件中的password为bcrypt加密后的密码,并制定加密策略为bcrypt-->
                <security:user name="user" password="{bcrypt}$2a$10$5r/POyb7K2wtbljfaY48K.1ie0l0qbuXYAdfdBEhVy1HLC3oqkix6"
                               authorities="ROLE_USER" />
                <security:user name="admin" password="{bcrypt}$2a$10$5r/POyb7K2wtbljfaY48K.1ie0l0qbuXYAdfdBEhVy1HLC3oqkix6"
                               authorities="ROLE_ADMIN" />
            </security:user-service>

2.使用SpringSecurityConfig配置类

创建SpringSecurityConfig配置类,继承WebSecurityConfigurerAdapter,并且该类需要加上@EnableWebSecurity注解,该类里面通常要写3个方法:

忽略某些配置的方法

public void configure(WebSecurity web) throws Exception {}
配置对应地址拦截请求的方法,例如拦截地址、关闭csrf、

protected void configure(HttpSecurity http) throws Exception {}
授权用户,比如创建某些账号,某些账号就可以登录了

protected void configure(AuthenticationManagerBuilder auth) throws Exception {}
@Component
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * UserServiceImpl是UserDetailsService的实现类,也就是写的认证类。
     */
    @Autowired
    private IUserService userService;

    /***
     * 忽略安全过滤
     * @param web
     * @throws Exception
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        //忽略相关地址
        web.ignoring().antMatchers("/images/**");
        web.ignoring().antMatchers("/js/**");
        web.ignoring().antMatchers("/login.html");
        web.ignoring().antMatchers("/error.html");
    }


    /***
     * 请求拦截配置
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //拦截规则配置
        http.authorizeRequests()
       			 //ADMIN角色可以访问/pages/下的所有文件
                .antMatchers("/pages/**").access("hasRole('ADMIN')")   
                 //USER角色可以访问/jsp/下的所有文件 
                .antMatchers("/jsp/**").access("hasRole('USER')")      
                 //指定登录页和处理登录的地址
                 //.and().formLogin().loginPage("/login.html").loginProcessingUrl("/login")   
                 //指定登出页和登出后让session无效    
                //.and().logout().logoutUrl("/logout").invalidateHttpSession(true);               
	
		  //登录相关配置
          http.formLogin().loginPage("/login.html")   //指定登录地址
                .loginProcessingUrl("/login")       //指定处理登录的请求地址
                .defaultSuccessUrl("/success.html",true); //登录成功后总是跳转到/admin/index.html页面

        //登出配置
        http.logout().logoutUrl("/logout").invalidateHttpSession(true); //登出地址为/logout,并且登出后销毁session

        //设置用户只允许在一处登录,在其他地方登录则挤掉已登录用户,被挤掉的已登录用户则需要返回/login.html重新登录
        http.sessionManagement().maximumSessions(1).expiredUrl("/login.html");
        
        //关闭CSRF安全策略
        http.csrf().disable();
	
		/允许跳转显示iframe
        http.headers().frameOptions().disable();

        //异常处理,例如403
        http.exceptionHandling().accessDeniedPage("/error.html");

        //只允许一个用户登录,如果同一个账户两次登录,那么第一个账户将被踢下线,跳转到登录页面
        http.sessionManagement().maximumSessions(1).expiredUrl("/login.html");
    }


    /***
     * 创建用户并授权
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //方式1:创建一个用户存在内存中,账号是admin,密码是123456,角色是ROLE_ADMIN
        auth.inMemoryAuthentication().withUser("admin").password("admin").roles("ADMIN");
        auth.inMemoryAuthentication().withUser("user").password("user").roles("USER");
   		
   		 //方式2:自定义认证类后注册自定义认证类
       // auth.userDetailsService(userService);
    }
}

执行测试

创建一个index.html页面,当访问index.html时会弹出登录窗口,这是由于设置http的auto-config=”true”时Spring Security自动生成的。

在这里插入图片描述

错误用户名与密码登陆

在这里插入图片描述

使用用户名:user与密码:user登陆

在这里插入图片描述

使用用户名:admin和密码:admin登陆,报错403,权限不足。

因为<security:intercept-url pattern="/**" access="ROLE_USER" />配置访问url需要ROLE_USER角色,admin具有ROLE_ADMIN。

在这里插入图片描述

三、自定义登陆页面

spring-security.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:security="http://www.springframework.org/schema/security"
       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.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">

    <!-- 配置不过滤的资源(静态资源及登录相关) -->
    <security:http security="none" pattern="/login.html" />
    <security:http security="none" pattern="/failer.html" />
    <security:http auto-config="true" use-expressions="false" >

        <!-- 配置资源连接,表示任意路径都需要ROLE_USER权限 -->
        <security:intercept-url pattern="/**" access="ROLE_USER" />

        <!-- 自定义登陆页面,login-page:自定义登陆页面
        authentication-failure-url:用户权限校验失败之后跳转页面,如果数据库中没有这个用户则不会跳转到这个页面。
        default-target-url:登陆成功后跳转页面。
        登陆页面固定属性:用户名:username,密码:password,action:login -->
        <security:form-login login-page="/login.html"
                             login-processing-url="/login" username-parameter="username"
                             password-parameter="password" authentication-failure-url="/failer.html"
                             default-target-url="/success.html" authentication-success-forward-url="/success.html"
        />

        <!-- 关闭CSRF,默认是开启的 -->
        <security:csrf disabled="true" />
    </security:http>
    <security:authentication-manager>
        <security:authentication-provider>
            <security:user-service>
                <security:user name="user" password="{noop}user"
                               authorities="ROLE_USER" />
                <security:user name="admin" password="{noop}admin"
                               authorities="ROLE_ADMIN" />
            </security:user-service>
        </security:authentication-provider>
    </security:authentication-manager>
</beans>

<csrf disabled="true"/> 为关闭跨域请求伪造控制。自定义登录静态页无法动态生成token,需要将此功能关闭。而spring security提供的表单默认有一个隐藏表单域,携带有token。一般静态页采用图形验证码的方式实现防止跨域请求伪造的功能。

创建页面

创建login.html,success.html,failer.html页面
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Login</title>
</head>
<body>
<form action="login" method="post">
    <h1>自定义登陆表单</h1>
    <table>
        <tr>
            <td>用户名:</td>
            <td><input type="text" name="username"/></td>
        </tr>
        <tr>
            <td>密码:</td>
            <td><input type="password" name="password"/></td>
        </tr>
        <tr>
            <td colspan="2" align="center"><input type="submit" value="登录"/>
                <input type="reset" value="重置"/></td>
        </tr>
    </table>
</form>
</body>
</html>

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <h1>登陆成功!</h1>
    </body>
    </html>

执行测试

在这里插入图片描述

错误的用户名与密码登陆

在这里插入图片描述

正确的账户名与密码登陆

在这里插入图片描述

四、基于数据库认证使用Spring Security

Spring Security使用数据库认证登陆涉及常用类:UserDetails、UserDetailsService

UserDetails是一个接口,用于封装当前进行认证的用户信息,可以对其进行实现,也可以使用Spring Security提供的一个UserDetails的实现类User来完成相应操作

public interface UserDetails extends Serializable {

	//账户所属角色集合
    Collection<? extends GrantedAuthority> getAuthorities();

    String getPassword();

    String getUsername();
	
	//帐户是否过期
    boolean isAccountNonExpired();

	//帐户是否锁定
    boolean isAccountNonLocked();

	//认证是否过期
    boolean isCredentialsNonExpired();

	//帐户是否可用
    boolean isEnabled();
}
UserDetailsService:让自己的userService实现UserDetailsService接口,重写loadUserByUsername方法,实现认证逻辑,返回UserDetails
public interface UserDetailsService {
    UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;
}

配置spring-security.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:security="http://www.springframework.org/schema/security"
       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.xsd
    http://www.springframework.org/schema/security
    http://www.springframework.org/schema/security/spring-security.xsd">

    <!-- 配置不拦截的资源 -->
    <security:http pattern="/login.html" security="none"/>
    <security:http pattern="/failer.html" security="none"/>
    <security:http pattern="/css/**" security="none"/>
    <security:http pattern="/img/**" security="none"/>
    <security:http pattern="/js/**" security="none"/>
    
    <!--auto-config="true":使用框架提供的默认登录页面
    	use-expressions="false":是否使用SPEL表达式
    -->
    <security:http auto-config="true" use-expressions="false">
    
        <!-- 配置具体的拦截规则 
        pattern:请求路径的规则 
        access:访问系统必须拥有的角色 -->
        <security:intercept-url pattern="/**" access="ROLE_USER,ROLE_ADMIN"/>

        <!-- 自定义登陆页面,定义跳转的具体的页面 -->
        <security:form-login
                login-page="/login.html"
                login-processing-url="/login"
                default-target-url="/success.html"
                authentication-failure-url="/failer.html"
                authentication-success-forward-url="/success.html"
        />

        <!-- 关闭跨域请求 -->
        <security:csrf disabled="true"/>
        
        <!-- 退出 -->
        <security:logout invalidate-session="true" logout-url="/logout" logout-success-url="/login.html" />

    </security:http>

    <!-- 使用数据库中的用户名和密码进行认证登陆 -->
    <security:authentication-manager>
        <security:authentication-provider user-service-ref="userService">
        </security:authentication-provider>
    </security:authentication-manager>

</beans>

认证实现

public interface IUserService extends UserDetailsService {
}
@Service("userService")
public class UserServiceImpl implements IUserService {
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        //TODO 查询数据库进行认证逻辑

        //模拟查询得到的用户信息
        String userName="user";
        String password="user";

        //构建角色集合,用户所拥有的角色
        List<SimpleGrantedAuthority> roleList = new ArrayList<>();
        roleList.add(new SimpleGrantedAuthority("ROLE_USER"));

        //处理用户对象封装成UserDetails
        UserDetails user=new User(userName,"{noop}"+password,roleList);

        /**
         * username 用户名
         * password 密码
         * enabled 帐户是否可用
         * accountNonExpired 帐户是否过期
         * credentialsNonExpired 认证是否过期
         * accountNonLocked 帐户是否锁定
         * authorities 账户所属角色集合
         */
        // User user = new User(userName, "{noop}"+password, true, true, true, true, roleList);
        return user;
    }
}

退出操作

 <!-- 退出 -->
        <security:logout invalidate-session="true" logout-url="/logout" logout-success-url="/login.html" />

五、密码加密

BCrypt加密算法

用户表的密码通常使用MD5等不可逆算法加密后存储,为防止彩虹表破解更会先使用一个特定的字符串(如域名)加密,然后再使用一个随机的salt(盐值)加密。 特定字符串是程序代码中固定的,salt是每个密码单独随机,一般给用户表加一个字段单独存储。 BCrypt算法将salt随机并混入最终加密后的密码,验证时也无需单独提供之前的salt,从而无需单独处理salt问题。

由于md5对密码进行编码,每次算出的md5值都一样,这样非常不安全,Spring Security推荐使用BCryptPasswordEncoder对密码加随机盐,每次的Hash值都不一样,安全性高。

BCrypt官网 http://www.mindrot.org/projects/jBCrypt/
在这里插入图片描述

spring security官方推荐使用更加安全的bcrypt加密方式。spring security 5支持的加密方式有bcrypt、ldap、MD4、MD5、noop、pbkdf2、scrypt、SHA-1、SHA-256、sha256。

在这里插入图片描述
使用BCrypt

从官网下载源码后,将类BCrypt拷贝到工程即可使用.

    public static void main(String[] args) {
        //随机生成盐,共29个字符
        String gensalt = BCrypt.gensalt();
        System.out.println(gensalt);
        //根据盐对密码进行加密
        String password = BCrypt.hashpw("12345", gensalt);
        //加密后的字符串前29位就是盐
        System.out.println(password);

        //密码校验
        boolean checkpw = BCrypt.checkpw("12345", "$2a$10$5r/POyb7K2wtbljfaY48K.1ie0l0qbuXYAdfdBEhVy1HLC3oqkix6");
        System.out.println(checkpw);
    }
$2a$10$5r/POyb7K2wtbljfaY48K.
$2a$10$5r/POyb7K2wtbljfaY48K.1ie0l0qbuXYAdfdBEhVy1HLC3oqkix6
true
-----------------------------------------------------------
$2a$10$tHA2ZoRl2zX33wFmovKnr.
$2a$10$tHA2ZoRl2zX33wFmovKnr.e8qbj8/WSCmqSGXCurC.RAZPDJh7DfS
false

使用BCryptPasswordEncoder

真实开发中使用BCryptPasswordEncoder进行加密与校验。

 @Test
    public void passwrodEncoderTest(){
        //原始密码
        String password = "123";
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        //使用BCrypt加密,每次加密使用一个随机盐
        for(int i=0;i<5;i++){
            String encode = bCryptPasswordEncoder.encode(password);
            System.out.println(encode);
            //校验
            boolean matches = bCryptPasswordEncoder.matches(password, encode);
            System.out.println(matches);
        }

    }

配置加密

1.使用spring-security.xml配置

   <!--使用自定义的认证类来认证用户信息-->
    <security:authentication-manager>
        <security:authentication-provider user-service-ref="userService">
            <!-- 配置加密的方式-->
                <security:password-encoder ref="passwordEncoder"/>
        </security:authentication-provider>
    </security:authentication-manager>

    <!-- 配置加密类 -->
    <bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>

2.使用配置类SpringSecurityConfig

<!--加密对象-->
<beans:bean id="bcryptEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
    @Autowired
    private IUserService userService;

    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    /****
     * 用户授权
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //使用自定义的认证类实现授权
        auth.userDetailsService(userService)
                .passwordEncoder(bCryptPasswordEncoder);    //指定加密对象
    }
执行测试,生成;明文密码的加密密码
   public static void main(String[] args) {
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String encode = bCryptPasswordEncoder.encode("user");
        System.out.println("encode = " + encode );
    }

encode = $2a$10$MQbfiELMnj4qtHCPe80mz.ZOHxzh1pcfgblgI0BGpg73Xekp/YjSm
在userServiceImpl的登陆认证方法中,修改模拟用户的明文密码为加密密码,此时,就可以省略密码前的{noop}标识。
@Service("userService")
public class UserServiceImpl implements IUserService {

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        //TODO 查询数据库进行认证逻辑

        //模拟查询得到的用户信息
        String userName="user";
        String password="$2a$10$MQbfiELMnj4qtHCPe80mz.ZOHxzh1pcfgblgI0BGpg73Xekp/YjSm";

        //用户所拥有的角色
        List<SimpleGrantedAuthority> roleList = new ArrayList<>();
        roleList.add(new SimpleGrantedAuthority("ROLE_USER"));

        //处理用户对象封装成UserDetails
        UserDetails user=new User(userName,password,roleList);

        /**
         * username 用户名
         * password 密码
         * enabled 帐户是否可用
         * accountNonExpired 帐户是否过期
         * credentialsNonExpired 认证是否过期
         * accountNonLocked 帐户是否锁定
         * authorities 账户所属角色集合
         */
        // User user = new User(userName, "{noop}"+password, true, true, true, true, roleList);
        return user;
    }
}
浏览器访问登陆

在这里插入图片描述

六、基于方法的权限控制

通过Spring security提供的注解对方法来进行权限控制,Spring Security在方法的权限控制上支持三种类型的注解,JSR-250注解、@Secured注解和支持表达式的注解,这三种注解默认都是没有启用的,需要单独通过global-method-security元素的对应属性进行启用。

JSR-250注解

1.添加依赖
 	<dependency>
         <groupId>javax.annotation</groupId>
         <artifactId>jsr250-api</artifactId>
        <version>1.0</version>
    </dependency>
2.spring-security.xml添加配置
 <security:global-method-security  jsr250-annotations="enabled"></security:global-method-security>

3.注解说明

@RolesAllowed:表示访问对应方法时所应该具有的角色。例如:@RolesAllowed({“USER”, “ADMIN”}) :表示该方法只要具有”USER”, “ADMIN”任意一种权限就可以访问。可以省略前缀ROLE_,实际的权限可能是ROLE_ADMIN

@PermitAll表示允许所有的角色进行访问,也就是说不进行权限控制

@DenyAll是和PermitAll相反的,表示无论什么角色都不能访问

4.使用注解
@Controller
public class TestController {
    @RequestMapping("/test1.do")
    @RolesAllowed("ADMIN")
    public String test1(){
        return "test1";
    }
}
5.若jsr250注解不生效,需要在springmvc.xml中开启对AOP的支持,以及相关依赖包
  <aop:aspectj-autoproxy proxy-target-class="true"/>
6.浏览器访问登陆,使用userServiceImpl类中模拟用户(用户名:user 密码:user 角色:ROLE_USER)

在这里插入图片描述

7.spring-security.xml配置的资源拦截规则,ROLE_USER允许访问,所以user登陆成功

在这里插入图片描述

8.由于test1.do资源访问需要ADMIN角色,而user用户无此角色,访问将报错403,可在web.xml中指定403错误跳转页面。
 <error-page>
    <error-code>403</error-code>
    <location>/403.jsp</location>
  </error-page>

在这里插入图片描述

@Secured注解

被@Secured注解标注的方法会得到权限控制的支持,其值默认为disabled,需要开启注解支持。

@Secured(“ROLE_ADMIN”):不可以省略前缀ROLE_,否则即使拥有某个权限也会报错403权限不足。

1.	spring-security.xml添加配置
 <security:global-method-security secured-annotations="enabled"></security:global-method-security>
2.使用注解
@Controller
public class TestController {
    @RequestMapping("/test1.do")
    @Secured("ROLE_ADMIN")
    public String test1(){
        return "test1";
    }
}
3.执行测试,效果同使用JSR-250注解

支持表达式的注解

@PreAuthorize 在方法调用之前,基于表达式的计算结果判断是否拥有对应权限

@PostAuthorize 在方法调用之后,如果表达式计算结果为false,将抛出一个安全性异常

@PostFilter 允许方法调用,但必须按照表达式来过滤方法的结果

@PreFilter 允许方法调用,但必须在进入方法之前过滤输入值

表达式 描述
hasRole([role]) 当前用户是否拥有指定角色。
hasAnyRole([role1,role2]) 多个角色是一个以逗号进行分隔的字符串。如果当前用户拥有指定角色中的任意一个则返回true。
hasAuthority([auth]) 等同于hasRole
hasAnyAuthority([auth1,auth2]) 等同于hasAnyRole
Principle 代表当前用户的principle对象
authentication 直接从SecurityContext获取的当前Authentication对象
permitAll 总是返回true,表示允许所有的
denyAll 总是返回false,表示拒绝所有的
isAnonymous() 当前用户是否是一个匿名用户
isRememberMe() 表示当前用户是否是通过Remember-Me自动登录的
isAuthenticated() 表示当前用户是否已经登录认证成功了。
isFullyAuthenticated() 如果当前用户既不是一个匿名用户,同时又不是通过Remember-Me自动登录的,则返回true。
1.spring-security.xml添加配置
 <security:global-method-security pre-post-annotations="enabled"></security:global-method-security>
2.使用注解
@Controller
public class TestController {
    @RequestMapping("/test1.do")
    @PreAuthorize("hasRole('ROLE_ADMIN')")
    public String test1(){
        return "test1";
    }

    @RequestMapping("/test2.do")
    @PreAuthorize("authentication.principal.username=='user'")
    public String test2(){
        return "test1";
    }
}
3.user用户只拥有USER角色,访问test1.do需要ADMIN角色,所以访问失败。

在这里插入图片描述

4.user用户用户名是“user”,满足访问test2.do的表达式条件,所以访问成功。

在这里插入图片描述

七、基于页面端标签控制权限

在jsp页面中可以使用spring security提供的权限标签来进行权限控制。

1.添加坐标依赖
   <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-taglibs</artifactId>
            <version>${spring.security.version}</version>
        </dependency>
2.Jsp页面导入标签
<%@taglib uri="http://www.springframework.org/security/tags" prefix="security"%>
3.标签说明

1.authentication

<security:authentication property="" htmlEscape="" scope="" var=""/>

authentication代表的是当前认证对象,可以获取当前认证对象信息,例如用户名。

property: 只允许指定Authentication所拥有的属性,可以进行属性的级联获取,如“principle.username”,不允许直接通过方法进行调用

htmlEscape:表示是否需要将html进行转义。默认为true。

scope:与var属性一起使用,用于指定存放获取的结果的属性名的作用范围,默认我pageContext。Jsp中拥有的作用范围都进行进行指定

var: 用于指定一个属性名,这样当获取到了authentication的相关信息后会将其以var指定的属性名进行存放,默认是存放在pageConext中

2.authorize

<security:authorize access="" method="" url="" var=""></security:authorize>

authorize是用来判断普通权限的,通过判断用户是否具有对应的权限而控制其所包含内容的显示

access: 需要使用表达式来判断权限,当表达式的返回结果为true时表示拥有对应的权限

method:method属性是配合url属性一起使用的,表示用户应当具有指定url指定method访问的权限,method的默认值为GET,可选值为http请求的7种方法

url:url表示如果用户拥有访问指定url的权限即表示可以显示authorize标签包含的内容

var:用于指定将权限鉴定的结果存放在pageContext的哪个属性中

3.accesscontrollist

<security:accesscontrollist hasPermission="" domainObject="" var=""></security:accesscontrollist>

accesscontrollist标签是用于鉴定ACL权限的。其一共定义了三个属性:hasPermission、domainObject和var,其中前两个必须指定

hasPermission:hasPermission属性用于指定以逗号分隔的权限列表

domainObject:domainObject用于指定对应的域对象

var:var则是用以将鉴定的结果以指定的属性名存入pageContext中,以供同一页面的其它地方使用

4.使用标签
<%@taglib prefix="security" uri="http://www.springframework.org/security/tags" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>我是Test1</h1>
<hr>

<p>
    当前登陆人: <security:authentication property="principal.username"></security:authentication>
</p>

<hr>

<ul>
    <li>
        <security:authorize access="hasRole('ADMIN')">用户管理</security:authorize>
    </li>
    <li>
        <security:authorize access="hasRole('USER')">角色管理</security:authorize>
    </li>
</ul>
</body>
</html>

5.由于spring-security.xml中,配置use-expressions="false",表示不使用el表达式,在页面中使用标签是会报错,解决方法如下:
方法一:spring-security.xml中配置一个bean

 <bean id="webexpressionHandler" class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler" />

方法二:spring-security.xml启用el表达式

    <security:http auto-config="true" use-expressions="true">
        <security:intercept-url pattern="/**" access="hasAnyRole('ROLE_USER','ROLE_ADMIN')"/>
    </security:http>
6.执行测试

在这里插入图片描述

八、AuthenticationSuccessHandler实现登录日志记录

spring security提供了一个叫“登录成功处理器”的组件,可以实现在登录后进行的后续处理逻辑。

public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler {
    
    /**
     * 登录后执行该方法
     *
     * @param httpServletRequest
     * @param httpServletResponse
     * @param authentication      用户信息
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
        System.out.println("登录成功,记录日志");

        String loginName = authentication.getName();
        System.out.println(loginName);
        String ip = httpServletRequest.getRemoteAddr();
        System.out.println(ip);

        httpServletRequest.getRequestDispatcher("/success.html").forward(httpServletRequest, httpServletResponse);
    }
}

修改spring-security.xml

<beans:bean id="loginHandler"   class="cn.ybzy.config.AuthenticationSuccessHandlerImpl"></beans:bean>

 <!-- 设置登陆成功处理器 -->
        <security:form-login
                authentication‐success‐handler‐ref="loginHandler"/>
        />

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/137089.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!