转自:http://justinrodenbostel.com/2014/05/30/part-5-integrating-spring-security-with-spring-boot-web/

PART 5: INTEGRATING SPRING SECURITY WITH SPRING BOOT WEB

Spring Boot provides utilities for quick and easy setup of Spring Security via auto-configuration and Java-based configuration. The getting started guide is quick and easy leads through configuring an in-memory AuthenticationManager in just minutes. Going beyond these examples, this installation will quickly review the getting started guide provided at Spring.io, and conclude with the configuration of a datasource-backed AuthenticationManager that uses Spring Data JPA, and the MySQL database platform.

As usual, for this installment, I’ve created a copy of the code from Part 4 and created a new project called Part 5. It’s committed to Github, ready for cloning.

Updating Dependencies
To install Spring Security, we first need to update our gradle script to include a dependency on spring-boot-starter-security. Update build.gradle to include the following dependency as seen below.

/build.gradle:

1
2
3
4
5
6
7
dependencies {
    compile("org.springframework.boot:spring-boot-starter-web")
    compile("org.springframework.boot:spring-boot-starter-security")
    compile("org.thymeleaf:thymeleaf-spring4:2.1.2.RELEASE")
    testCompile("junit:junit")
}

Following that, executing a build should pull in our new dependencies.

Creating The Security Configuration
Continuing to lift code from the Spring.io docs for review, below you’ll find the example of the base Java security configuration. We’ll review the important bits after the jump. We’ll create this in the same directory as our other configuration files:

/src/main/java/com.rodenbostel.sample/SecurityConfiguration.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
packagecom.rodenbostel.sample;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.Configuration;
importorg.springframework.security.authentication.AuthenticationManager;
importorg.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
importorg.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
importorg.springframework.security.config.annotation.web.builders.HttpSecurity;
importorg.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
importorg.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
importorg.springframework.security.web.util.matcher.AntPathRequestMatcher;
@Configuration
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(prePostEnabled =true)
publicclassSecurityConfiguration extendsWebSecurityConfigurerAdapter {
    @Override
    protectedvoidconfigure(HttpSecurity http) throwsException {
        http
                .authorizeRequests().anyRequest().authenticated();
        http
                .formLogin().failureUrl("/login?error")
                .defaultSuccessUrl("/")
                .loginPage("/login")
                .permitAll()
                .and()
                .logout().logoutRequestMatcher(newAntPathRequestMatcher("/logout")).logoutSuccessUrl("/login")
                .permitAll();
    }
    @Override
    protectedvoidconfigure(AuthenticationManagerBuilder auth) throwsException {
        auth.inMemoryAuthentication().withUser("user").password("password").roles("USER");
    }
}

As usual, the @Configuration annotation lets Spring know that this file contains configuration information. The next two annotations (@EnableWebMvcSecurity and @EnableGlobalMethodSecurity(prePostEnabled=true)) setup the automatically-configured portions of our security scheme, provided by Spring-Boot. EnableWebMvcSecurity basically pulls in the default SpringSecurity/SpringMVC integration. It’s an extension of theWebMvcConfigurerAdapter, and adds methods for handling and generating CSRF tokens and resolving the logged in user, and configures default AuthenticationManagers and Pre/Post object authorization implementations. The @EnableGlobalMethodSecurity sets up processors for authorization advice that can be added around methods and classes. This authorization advice lets a developer write Spring EL that inspects input parameters and return types.

Our SecurityConfiguration class also extends WebSecurityConfigurerAdapter. In Spring/Spring Boot, Configurer Adapters are classes that construct default bean configurations and contain empty methods which are meant to be overridden. Overriding these methods allow a developer to customize the Web Security Configuration during startup. Typically, the default configurations are constructed, and immediately following, the empty methods are called. If you’ve overridden an empty method, you’re able to inject custom behavior into the default configuration during the startup of the container.

In our case, the two coded parts of our SecurityConfiguration class (two methods named “configure”) are examples of these empty methods meant to be overridden. During container startup, after the HttpSecurity object’s default configuration is specified, our overridden method is called. Here we are able to customize the default configuration by specifying which requests to authorize, and how to route various security-related requests: default success URL, error routing, where to send logouts, etc. Also during container startup, after the AuthenticationManagerBuilder is configured, our configure method is called, and in this case we’re altering the default configuration, giving instructions to the AuthenticationManagerBuilder to build an in-memory AuthenticationManager with a default user credential and role.

You’ll notice in this configuration we’ve specified several URL paths that do not exist. There’s no login page or controller, and no way for a user to interact with the security configuration when the app is started up. Next, we’ll need to construct and wire in a login page to complete our beginning configuration.

Building The Login Page
The login page in the Spring.io sample is very straightforward. Just a simple form with an input for username and password. Let’s build that and review a few key parts.

/src/main/resources/templates/login.html:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPEhtml>
<htmlxmlns="http://www.w3.org/1999/xhtml"xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
    <title>Spring Security Example</title>
</head>
<body>
<divth:if="${param.error}">
    Invalid username and password.
</div>
<divth:if="${param.logout}">
    You have been logged out.
</div>
<formth:action="@{/login}"method="post">
    <div><label> User Name : <input type="text"name="username"/> </label></div>
    <div><label> Password: <input type="password"name="password"/> </label></div>
    <div><inputtype="submit"value="Sign In"/></div>
</form>
</body>
</html>

Most importantly, we have inputs with the names of “username” and “password”. These are the Spring Security defaults. If you’re routing a request to Spring Security to authenticate, these are the parameters on the request that it will be looking for. Next, you’ll also notice that there are Thymeleaf conditionals (th:if) for displaying logout and error messages if they are present in the response parameters during rendering. You’ll also notice the path to this page is “/login”, and the action on this form routes back to “/login” – but we don’t have those registered anywhere…

Registering the Login Action
The path our login form is posting to is the default used by Spring Security. This is where what used to be called the “j_spring_security_check” servlet is listening for requests to authenticate. The request path (where we’re retrieving the login form by issuing a GET to /login) is normally mapped to a controller, but in this case, since we’re using automatically configured features of Spring Boot, we need to specify this mapping in our application configuration. Add the code below to your application configuration. You may notice the use of another @Override method – another hook where we can add logic to customize our application…

/src/main/java/com.rodenbostel.sample.Application.java:

1
2
3
4
@Override
publicvoidaddViewControllers(ViewControllerRegistry registry) {
    registry.addViewController("/login").setViewName("login");
}

Log In!
Start your server, and try to access the app again. For me, that’s simply visitinghttp://localhost:8080.

I’m immediately challenged.

If I put in an invalid username or password, we should see an error:

If I put in the correct credentials (id: user/password: password), we should be able to log in:

There’s quite a bit missing here still – let’s take this example a bit further – we’ll wire in components that would make this configuration closer to production ready – an AuthenticationManager backed by JDBC, configurable password encoders, and a UserDetailsService implementation that we can use to manage users.

Beyond The Examples
To begin taking steps closer to this solution being production-ready, we first need to back our app with a database. I’ll be using MySQL. I’ll assume you’ve got it installed and running (if you’re on a mac, I’d use Homebrew to accomplish that.

First, we’ll add the MySQL dependency to our gradle script:

/build.gradle:

1
2
3
4
5
6
7
8
9
dependencies {
    compile("org.springframework.boot:spring-boot-starter-web")
    compile("org.springframework.boot:spring-boot-starter-security")
    compile("org.springframework.boot:spring-boot-starter-data-jpa")
    compile("org.thymeleaf:thymeleaf-spring4:2.1.2.RELEASE")
    runtime('mysql:mysql-connector-java:5.1.6')
    testCompile("junit:junit")
}

Configuring A Datasource
I’ll be calling my schema in MySQL “beyond-the-examples”. I’ll assume you’ve used the same name. Conveniently, Spring Boot Starter projects have an automatically configured property source path. This means that using a properties file for configuration data we’d like to externalize simply requires creating an “application.properties” file and putting it somewhere on the application’s classpath. We’ll create that file now, and add properties that we’ll use to set up our datasource.

/src/main/resources/application.properties:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
spring.datasource.url=jdbc:mysql://localhost:3306/beyond-the-examples
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.jpa.hibernate.dialect= org.hibernate.dialect.MySQLInnoDBDialect
spring.jpa.generate-ddl=false
1
You can see I’m using thedefaultconfiguration forMySQL.  I wouldn’t recommend that forproduction.
Next, we’ll build references to these properties in our application’s configuration, so that we can use them to create a datasource bean that we can inject into our security configuration.  Update the application configuration file to add these properties:
/src/main/java/com.rodenbostel.sample.Application.java:
1
    @Value("${spring.datasource.driverClassName}")
    privateString databaseDriverClassName;
    @Value("${spring.datasource.url}")
    privateString datasourceUrl;
    @Value("${spring.datasource.username}")
    privateString databaseUsername;
    @Value("${spring.datasource.password}")
    privateString databasePassword;
1
Next create a Datasource@Beanusing these properties in the same file.
/src/main/java/com.rodenbostel.sample.Application.java:
1
    @Bean
    publicDataSource datasource() {
        org.apache.tomcat.jdbc.pool.DataSource ds =neworg.apache.tomcat.jdbc.pool.DataSource();
        ds.setDriverClassName(databaseDriverClassName);
        ds.setUrl(datasourceUrl);
        ds.setUsername(databaseUsername);
        ds.setPassword(databasePassword);
        returnds;
    }

Now, we have a datasource configured that we can @Autowire into any of our Spring beans, configuration or otherwise.

Create the Spring Security Tables
The DDL from the Spring.io docs is for HSQLDB. It’s syntax is not compliant with MySQL. Shout out to this guy (http://springinpractice.com/2010/07/06/spring-security-database-schemas-for-mysql) for publishing the MySQL versions of the default Spring Security schema. If you’re using MySQL like me, use the DDL from that blog to create a “users” table and an “authorities” table, then thank him. Since we’ll be properly encoding our passwords, we may want to make that password column a bit wider. Here’s what I ran:

1
createtableusers (    username varchar(50)notnull primary key,   passwordvarchar(255)notnull,    enabled booleannotnull) engine = InnoDb;createtableauthorities (    username varchar(50)notnull,    authorityvarchar(50)notnull,   foreignkey(username)referencesusers (username),    uniqueindex authorities_idx_1 (username, authority)) engine = InnoDb;

Building The New Configuration
To start using the new datasource in the security configuration, we first need to wire the datasource bean into our SecurityConfiguration class. Update your SecurityConfiguration file to instruct spring to @Autowire this bean:

/src/main/java/com.rodenbostel.sample.SecurityConfiguration.java:

1
2
@Autowired
privateDataSource datasource;

Next, we’re going to make a few significant changes to our AuthenticationManagerBuilder configuration to reference this datasource and a few other things, which I’ll review after the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    @Override
    protectedvoidconfigure(AuthenticationManagerBuilder auth) throwsException {
        JdbcUserDetailsManager userDetailsService =newJdbcUserDetailsManager();
        userDetailsService.setDataSource(datasource);
        PasswordEncoder encoder =newBCryptPasswordEncoder();
        auth.userDetailsService(userDetailsService).passwordEncoder(encoder);
        auth.jdbcAuthentication().dataSource(datasource);
        if(!userDetailsService.userExists("user")) {
            List<GrantedAuthority> authorities =newArrayList<GrantedAuthority>();
            authorities.add(newSimpleGrantedAuthority("USER"));
            User userDetails =newUser("user", encoder.encode("password"), authorities);
            userDetailsService.createUser(userDetails);
        }
    }
1
Prior tothis, our AuthenticationManagerBuilder was configured on a single line - we were using an in-memory configuration, and creating a user directly on it.  Here, we’ll use the AuthenticationManagerBuilder to move from using:
1
auth.inMemoryAuthentication()

to using:

1
auth.jdbcAuthentication().dataSource(datasource);

Assuming there are already users in the database, believe it or not, that’s all we need to begin using the JDBC-backed AuthenticationManager. The requirement for creating new users and managing existing users is a foregone conclusion. In our case, we’d like to automatically configure a default user on app startup just like we were before. We can get a handle on the automatically configuration (by Spring Boot) UserDetailsService through our AuthenticationManagerBuilder at:

1
auth.getDefaultUserDetailsService();

…but that doesn’t quite do everything we need. On the first line of our updated AuthenticationManagerBuilder configuration method, you can see we’ve created a new instance of one of the provide implementations of UserDetailsService provided by Spring. If you don’t have a reason to customize how you manage users in your system, that is a perfectly suitable implementation, but there are things to consider. Please consult the API docs for more detail (http://docs.spring.io/spring-security/site/docs/3.2.4.RELEASE/apidocs/org/springframework/security/provisioning/JdbcUserDetailsManager.html). After creating the new reference to the JdbcUserDetailsManager, we need to set a reference to our datasource on it. Following that, we add our encoder for storing our passwords securely, and then we use the JdbcUserDetailsManager’s built-in functionality to check to see if our test user exists, and create him if he doesn’t.

Testing Again
Running the application should yield no change in behavior when compared with what we saw earlier. This is desired. What we will see that’s different will be in our database. Startup the app using: “gradle bootRun”, and using your favorite database management tool, query the database to see our newly create user and their encoded password:

Conclusion
I cobbled the information in this post from many sources – some I’ve remembered and have mentioned, and others I have not. I hope putting this information in a single post helps whoever stumbles upon it! That concludes this series of Spring Boot posts, but during the time I’ve been writing these, I’ve come up with two more topics to touch on, mostly surrounding further securing your app (http://www.jasypt.org/) and easier maintenance of your database tables (http://flywaydb.org/). Check back soon!

转载于:https://www.cnblogs.com/leonxyzh/p/7289012.html

PART 5: INTEGRATING SPRING SECURITY WITH SPRING BOOT WEB相关推荐

  1. 使用Spring Security在Spring Boot中进行缓存

    在这篇文章中,我想分享一下O&B的一个团队的经验教训. 他们正在使用带有Spring Security的Spring Boot. 默认情况下,Spring Security保护的所有内容都将通 ...

  2. Spring MVC实现Spring Security,Spring Stomp websocket Jetty嵌入式运行

    使用Spring框架各个组件实现一个在线聊天网页,当有用户连接WebSocket,服务器监听到用户连接会使用Stomp推送最新用户列表,有用户断开刷新在线列表,实时推送用户聊天信息.引入Jetty服务 ...

  3. spring security logout(spring security登出示例)

    ** spring security logout(spring security登出示例) ** 在学习实现spring security登出的时候发现了一篇外文,感觉写的挺好,这里斗胆尝试翻译出来 ...

  4. Spring Security with Spring Boot 2.0:使用Servlet堆栈的简单身份验证

    Spring安全性是一个很好的框架,可节省开发人员的大量时间和精力. 此外,它还具有足够的灵活性,可以自定义并满足您的需求. 随着spring的发展,spring安全性也使得在项目中设置安全性变得更加 ...

  5. Spring Security with Spring Boot 2.0:密码编码器

    在上一篇文章中,我们使用了用户详细信息服务,以便提供一种基于给定用户名从函数加载数据的方法. 用户详细信息的实现可能由内存机制,sql / no-sql数据库等支持. 选项是无限的. 关于密码存储,我 ...

  6. Spring Security——集成Spring Session、Redis和JSON序列化解决方案

    官方文档 https://docs.spring.io/spring-session/docs/2.4.2/reference/html5/#spring-security Maven 主要 < ...

  7. 【Spring Security】Spring Security框架详解

    文章目录 前言 一.框架概述 Spring Security的架构 Spring Security的主要特点 二.认证 HTTP Basic认证 表单登录 OpenID Connect 三.授权 基于 ...

  8. nacos oaut服务地址_用户认证的例子:Spring Security oAuth2 + Spring Cloud Gateway + Nacos + Dubbo...

    这个例子是商城后台项目的一部分,主要使用了oAuth2的密码模式完成用户名密码认证功能.主要流程是:使用Nacos作为注册中心,操作用户的服务user-mgr-service作为服务提供者,注册到Na ...

  9. 项目中Spring Security 整合Spring Session实现记住我功能

    Spring Session提供了与Spring Security的"我记得"身份验证的集成的支持: 目的: 更改会话过期长度 确保会话cookie在Integer.MAX_VAL ...

最新文章

  1. 题解 P4692 【[Ynoi2016]谁的梦】
  2. [新手-数据分析师]numpy学习笔记(2nd)
  3. web项目导入变java项目_eclipse导入web项目变成java项目解决办法
  4. 【spring boot】【thymeleaf】SPEL处理 null 值
  5. IOS7实现扫描二维码
  6. 清洁代码_清洁单元测试
  7. jQuery学习之八---文档处理
  8. 《数据库系统概念》19-并发控制
  9. 从设计模式到恋爱宝典,程序员们的福利来了
  10. HTML5(FileRdeader)
  11. Mac上的全局翻译利器 : Bob + PopClip
  12. 模具基础篇:直线度、平面度、圆度等这些形位公差你都了如指掌?
  13. java解析返回报文_Java解析json报文实例解析
  14. 阿里云服务器安全警告-异常网络连接-访问恶意域名
  15. iOS ● 非常全的三方库、插件、大牛博客等等
  16. 半中括号怎么用公式编辑器打?
  17. android 根据宽度调整字体大小,android 字体大小 根据分辨率 自动调整
  18. IT通过什么途径去美国工作?
  19. 企鹅,大鱼,百家,头条到底那个收益高,新手该怎么来做?
  20. 深入浅出计算机组成原理(四)——穿越功耗墙,我们该从哪些方面提升“性能”?

热门文章

  1. SonarQube4.4+Jenkins进行代码检查实例之二
  2. 在新浪潮中,服务教育是你的竞争利器
  3. 中青旅:在线旅游行业如何选型数据分析平台?
  4. QList模板类常用接口函数
  5. Centos7 下部署PPTP
  6. (五)开源IT资产管理系统--分发OCS客户端
  7. 关于maven仓库中的_remote.repositories
  8. Git 系列(七):使用 Git 管理二进制大对象
  9. Linux/Centos服务器安装portsentry防恶意端口扫描
  10. 手机进水的正确处理方法?