第一篇 spring security的简单入门

一、依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
        <relativePath/>
    </parent>

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.darren.test</groupId>
    <artifactId>security-test</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring.boot.version>2.2.1.RELEASE</spring.boot.version>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!-- test -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <version>${spring.boot.version}</version>
        </dependency>

        <!-- starter-web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>${spring.boot.version}</version>
        </dependency>

        <!-- security -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
            <version>${spring.boot.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

二、简单使用

需要手动实现或继承以下三个类:

1. UserDetailsService

该接口返回UserDetails对象,返回用户名、密码、权限等用户基本信息,实现类主要实现相关信息的获取。

@Service
public class UserDetailServiceImpl implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        List<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("role");
        return new User("darren", "123", auths);
    }
}

UserDetails为接口对象,需要进行实现。框架提供的实现类User基本够用。

GrantedAuthority为security提供的用于存储角色或权限信息的实体类,角色必须以“ROLE_”开头,权限不需要。

2. PasswordEncoder

密码加密接口实现,这里密码不加密。

public class NoEncryptPasswordEncoder implements PasswordEncoder {

    @Override
    public String encode(CharSequence charSequence) {
        return (String) charSequence;
    }

    @Override
    public boolean matches(CharSequence charSequence, String s) {
        return s.contentEquals(charSequence);
    }
}

3. WebSecurityConfigurerAdapter

该类为抽象类,提供继承以自定义安全配置。

@Configuration
@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailServiceImpl userDetailService;

    /**
     * 加密类
     * @return PasswordEncoder
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new NoEncryptPasswordEncoder();
    }

    /**
     * 配置登录实现类和密码加密类
     * @param auth AuthenticationManagerBuilder
     * @throws Exception 异常
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailService).passwordEncoder(passwordEncoder());
    }

    /**
     * 登录与权限配置
     * @param http HttpSecurity
     * @throws Exception 异常
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 自定义登录页面、登录接口、成功跳转,适用前后端不分离项目
        http.formLogin().loginPage("/login.html").loginProcessingUrl("/auth/login").defaultSuccessUrl("/test/home").permitAll()
                // 放行路径
                .and().authorizeRequests().antMatchers("/test/test1", "/test/test2").permitAll()
                // 登录管控路径
                .and().authorizeRequests().anyRequest().authenticated()
                // 关闭csrf防护
                .and().csrf().disable();
    }

    /**
     * 不定义没有password grant_type,密码模式需要AuthenticationManager支持
     * @return AuthenticationManager
     * @throws Exception 异常
     */
    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

简单说明:

(1)formLogin().loginPage("/login.html")自定义登录页面,不定义时使用默认页面。

(2)formLogin().loginProcessingUrl("/auth/login")定义登录路径,无需编写相关控制器,由框架配置。

(3).and()用于回到HttpSecurity,继续往后配置。

(4).authorizeRequests().antMatchers("/test/test1", "/test/test2"):访问路径在括号范围内。

(5).authorizeRequests().anyRequest():所有路径

(6).permitAll()放行

(7).authenticated()需要登录

(8)权限管控另有:hasRole()、hasAnyRole()、hasAuthority()、hasAnyAuthority(),分别是有某个角色、有括号中任意一个角色、有某个权限、有括号中的任意一个权限

附:

自定义的简单页面

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>登录页面</title>
    </head>
    <body>
    请登录:
    <form name="f" action="/auth/login" method="post">
        <br/>
        用户名:
        <input type="text" name="username" placeholder="name"><br/>
        密码:
        <input type="password" name="password" placeholder="password"><br/>
        <input name="submit" type="submit" value="提交">
    </form>
    </body>
</html>

三、异常处理

http.exceptionHanding().xxx

四、注解使用

1. @Secured

(1)含义:用户具有某个角色,可以访问方法。

(2)配置类或程序启动类上方添加@EnableGlobalMethodSecurity(securedEnabled = true),开启安全注解。

(3)在controller方法上使用该注解。例:@Secured("ROLE_ADMIN", "ROLE_GUEST")

(4)userDetailService中设置用户具体角色

2.@PreAuthorize

(1)方法执行之前进行权限检查

(2)配置类或程序启动类上方添加@EnableGlobalMethodSecurity(prePostEnabled = true),开启安全注解。

(3)在controller方法上使用该注解。例:

    /* 权限 */
    @PreAuthorize("hasAuthority('query')")
    @PreAuthorize("hasAnyAuthority('query', 'update')")
    /* 角色 */
    // 这里的hasRole/hasAnyRole不同于配置类,角色名需带上ROLE_前缀
    @PreAuthorize("hasRole('ROLE_ADMIN')")
    @PreAuthorize("hasAnyRole('ROLE_ADMIN', 'ROLE_GUEST')")

(4)userDetailService中设置用户具体权限

3.@PostAuthorize(使用低频)

方法执行后进行过滤,适合验证带有返回值的权限,其余同2。

4.@PostFilter(使用低频)

(1)在方法执行结束之后,对返回数据进行过滤,只返回满足条件的数据。

(2)filterObject是返回数据对象:

    @PostFilter("filterObject.username == 'admin1'")
    public List<Map<String, Object>> getAll() {
        ArrayList<Map<String, Object>> list = new ArrayList<>();
        for (int i = 1; i <= 2; i++) {
            Map<String, Object> map = new HashMap<>();
            map.put("no", i);
            map.put("username", "admin" + i);
            list.add(map);
        }
        return list;
    }

在循环结束后list包含username为admin1和admin2的记录。经过过滤最终只返回username为admin1的记录。

5.@PreFilter(使用低频)

(1)通过权限验证之后,方法执行之前,对传入数据进行过滤,只接收满足条件的数据。

(2)例:传入的list中只取id能被2整除的数据:@PreFilter(value = "filterObject.id % 2 == 0")

五、用户注销

http.logout().logout("/logout").logoutSuccessUrl("/test/out").permitAll();

与配置登录的方式差不多。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大迪吃小迪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值