When using Spring Security, we have summarized it in the form of reverse lookup. The answer here is not the correct answer, it is just one method, so I hope you can refer to it when you are unsure about implementation.
The reference will be updated from time to time.
item | version |
---|---|
Java | 8 |
Spring Boot | 2.2.4 |
Below is the minimum required code.
Limit all requests
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.authenticated();
}
}
Since we will not connect to the DB this time, we will use the following authentication information.
application.yml
spring:
security:
user:
name: user
password: pass
roles: USER
--(A), (B), etc. appear in the code, but this means that the same thing will be included. The scope is only on each reference. --The controller class for screen display (`` `@ Controller```) will be omitted, so please create it as appropriate.
SecurityConfig.java
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/","/login") // 「/」「/"login" can be accessed without authentication
.permitAll()
.anyRequest()
.authenticated();
}
}
CSRF is enabled by default.
SecurityConfig.java
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.authenticated();
http.csrf().disable();
}
}
SecurityConfig.java
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.authenticated();
http.cors().configurationSource(getCorsConfigurationSource());
}
private CorsConfigurationSource getCorsConfigurationSource() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
//Allow all methods
corsConfiguration.addAllowedMethod(CorsConfiguration.ALL);
//Allow all headers
corsConfiguration.addAllowedHeader(CorsConfiguration.ALL);
//Allow all origins
corsConfiguration.addAllowedOrigin(CorsConfiguration.ALL);
UrlBasedCorsConfigurationSource corsSource = new UrlBasedCorsConfigurationSource();
//Can be set for each path. Here set for all paths
corsSource.registerCorsConfiguration("/**", corsConfiguration);
return corsSource;
}
}
authenticationprovider
Create an implementation class for.
CustomeAuthenticationProvider.java
@Configuration
public class CustomeAuthenticationProvider implements AuthenticationProvider {
//Authentication process
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = (String) authentication.getPrincipal();
String password = (String) authentication.getCredentials();
if (!"user".equals(username) || !"password".equals(password)) {
throw new BadCredentialsException("Incorrect login information");
}
return new UsernamePasswordAuthenticationToken(username, password, new ArrayList<>());
}
@Override
public boolean supports(Class<?> authentication) {
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
}
}
securityconfig
Specify the provider created above in.
SecurityConfig.java
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomeAuthenticationProvider authenticationProvider;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.authenticated();
http.formLogin();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//Specify the Provider created above
auth.authenticationProvider(authenticationProvider);
}
}
SecurityConfig.java
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.authenticated();
http.formLogin();
}
}
/login
When you access, the login screen prepared by spring security is displayed.
Prepare the HTML for the login screen.
login.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Login</title>
</head>
<body>
<form th:action="@{/login}" method="post">
<input type="text" name="username">
<input type="password" name="password">
<button type="submit">Login</button>
</form>
</body>
</html>
SecurityConfig.java
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("(A)") //add to
.permitAll() //add to
.anyRequest()
.authenticated()
http.formLogin()
.loginPage("(A)"); //add to
}
}
By default, you get it with the parameter names username
and `` `password```.
SecurityConfig.java
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/(A)") //① pass
.permitAll()
.anyRequest()
.authenticated()
http.formLogin()
.loginPage("/(A)")
.usernameParameter("(B)") //add to
.passwordParameter("(C)"); //add to
}
}
login.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Login</title>
</head>
<body>
<form th:action="@{/login}" method="post">
<input type="text" name="(B)">
<input type="password" name="(C)">
<button type="submit">Login</button>
</form>
</body>
</html>
By default, it transitions to "/".
SecurityConfig.java
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.authenticated()
http.formLogin()
.defaultSuccessUrl("/home"); // 「/Transition to "home"
}
}
Normally, you are authenticated with two parameters, username
and `` `password```.
There are several methods, but here is the method for Form authentication.
Prepare a login screen to enter the three parameters.
login.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Login</title>
</head>
<body>
<form th:action="@{/login}" method="post">
<input type="text" name="(A)">
<input type="text" name="username">
<input type="password" name="password">
<button type="submit">Login</button>
</form>
</body>
</html>
Create a class that inherits UsernamePasswordAuthenticationToken
that holds the credentials.
MultiParamAuthenticationToken
public class MultiParamAuthenticationToken extends UsernamePasswordAuthenticationToken {
private static final long serialVersionUID = 1L;
private Object tenant; //Additional parameters
public MultiParamAuthenticationToken(Object principal, Object credentials, Object tenant) {
super(principal, credentials, Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER")));
this.tenant = tenant;
}
public Object getTenant() {
return this.tenant;
}
}
Create an authentication provider class.
MultiParamAuthenticationProvider
@Configuration
public class MultiParamAuthenticationProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = (String) authentication.getPrincipal();
String password = (String) authentication.getCredentials();
String tenant = null;
if (authentication instanceof MultiParamAuthenticationToken) {
tenant = (String) ((MultiParamAuthenticationToken) authentication).getTenant();
}
if (!"user".equals(username) || !"pass".equals(password) || !"multi".equals(tenant)) {
throw new BadCredentialsException("aaa");
}
return new MultiParamAuthenticationToken(username, password, tenant);
}
@Override
public boolean supports(Class<?> authentication) {
return MultiParamAuthenticationToken.class.isAssignableFrom(authentication);
}
}
Prepare a filter class to get the third parameter.
MultiParamAuthenticationFilter
public class MultiParamAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) {
String username = obtainUsername(request);
String password = obtainPassword(request);
String tenant = obtainTenant(request);
MultiParamAuthenticationToken authRequest = new MultiParamAuthenticationToken(
username, password, tenant);
return getAuthenticationManager().authenticate(authRequest);
}
private String obtainTenant(HttpServletRequest request) {
return (String) request.getParameter("tenant");
}
}
SecurityConfig.java
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MultiParamAuthenticationProvider authenticationProvider;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login")
.permitAll()
.anyRequest()
.authenticated();
//Set your own filter without using formLogin
http.addFilter(getMultiParamAuthenticationFilter());
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider);
}
private MultiParamAuthenticationFilter getMultiParamAuthenticationFilter() throws Exception {
MultiParamAuthenticationFilter filter = new MultiParamAuthenticationFilter();
filter.setAuthenticationManager(authenticationManager());
return filter;
}
}
In order to perform OAuth authentication, it is necessary to issue a client ID and secret at the authentication provider. Here, OAuth authentication is performed by Google.
Add the following dependency to pom.xml.
pom.xml
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
</dependency>
Set the OAuth information in application.yml.
application.yml
spring:
security:
oauth2:
client:
registration:
google:
clientId: <Client ID>
clientSecret: <Client secret>
SpringSecurity.java
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.authenticated();
http.oauth2Login(); //add to
}
LoginController.java
@Controller
public class LoginController {
@Autowired
private OAuth2AuthorizedClientService authorizedClientService;
@GetMapping
public String index(OAuth2AuthenticationToken authentication, Model model) {
OAuth2AuthorizedClient authorizedClient = this.authorizedClientService.loadAuthorizedClient(
authentication.getAuthorizedClientRegistrationId(),
authentication.getName());
model.addAttribute("name", authorizedClient.getPrincipalName());
model.addAttribute("accessToken", authorizedClient.getAccessToken().getTokenValue());
return "index";
}
oauth2authenticationtoken
You can get the authentication information with.
Next, create a screen for display.
index.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>home</title>
</head>
<body>
<p th:text="${accessToken}"></p>
<p th:text="${name}"></p>
</body>
</html>
Create a login screen.
login.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Login</title>
</head>
<body>
<a href="/oauth2/authorization/google">Google authentication</a>
</body>
</html>
SecurityConfig.java
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("(A)")
.permitAll()
.anyRequest()
.authenticated();
http.oauth2Login().loginPage("(A)"); //add to
}
usernamepasswordauthenticationfilter
Create a class that inherits from.
JsonAuthenticationFilter.java
public class JsonAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) {
try {
//Get parameters
//Authentication parameter information is request.getInputStream()Since it is stored in, it is taken out using Jackson
Map<String, String> params = new ObjectMapper().readValue(request.getInputStream(),
new TypeReference<Map<String, String>>() {});
//Authentication request information generation
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
params.get("(A)"), params.get("(B)"));
//Authentication
return getAuthenticationManager().authenticate(authRequest);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
//Process when authentication is successful
@Override
protected void successfulAuthentication(HttpServletRequest req,
HttpServletResponse res,
FilterChain chain,
Authentication auth) throws IOException, ServletException {
//Save authenticated user
//If you do not save it, it will be treated as unlogged in.
SecurityContextHolder.getContext().setAuthentication(auth);
}
}
The login screen will send the authentication information by Ajax communication.
login.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Login</title>
</head>
<body>
<form>
<input type="text" id="(A)" name="(A)">
<input type="password" id="(B)" name="(B)">
<button type="button" id="btnLogin" onclick="login()">Login</button>
</form>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
function login() {
//Get authentication parameters
const data = {
email: document.getElementById('(A)').value,
password: document.getElementById('(B)').value
}
//Authentication
axios.post('(C)', data)
.then(res => location.href = "/home") //When authentication is successful, "/Transition to "home"
}
</script>
</body>
</html>
Set the Filter created above with SecuritConfig.
SecurityConfig.java
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("(C)")
.permitAll()
.anyRequest()
.authenticated();
//Ajax communication is performed, so disable it
http.csrf().disable();
//Set authentication filter by Json
http.addFilter(getJsonAuthenticationFilter());
}
private JsonAuthenticationFilter getJsonAuthenticationFilter() throws Exception {
JsonAuthenticationFilter filter = new JsonAuthenticationFilter();
//Use default authentication method
filter.setAuthenticationManager(authenticationManager());
//Specify the path where the Filter will be executed and the HTTP method
filter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("(C)", "POST"));
return filter;
}
}
Add the JWT library to pom.xml.
pom.xml (additional only)
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
Send the credentials in JSON and return the JWT after success.
usernamepasswordauthenticationfilter
Create a class that inherits from.
JwtAuthenticationFilter.java
public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) {
try {
//Get parameters
//Authentication parameter information is request.getInputStream()Since it is stored in, it is taken out using Jackson
Map<String, String> params = new ObjectMapper().readValue(request.getInputStream(),
new TypeReference<Map<String, String>>() {});
//Authentication request information generation
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
params.get("(A)"), params.get("(B)"));
//Authentication
return getAuthenticationManager().authenticate(authRequest);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
//Create JWT when authentication is successful and set it in response header.
@Override
protected void successfulAuthentication(HttpServletRequest req,
HttpServletResponse res,
FilterChain chain,
Authentication auth) throws IOException, ServletException {
Date issuedAt = new Date();
Date notBefore = new Date(issuedAt.getTime());
Date expiresAt = new Date(issuedAt.getTime() + TimeUnit.MINUTES.toMillis(100L));
//JWT generation
String token = JWT.create()
.withIssuedAt(issuedAt)
.withNotBefore(notBefore)
.withExpiresAt(expiresAt)
.withClaim("(C)", (String)auth.getPrincipal())
.sign(Algorithm.HMAC512("secret"));
//Set JWT in Authorization header
res.addHeader("Authorization", "Bearer " + token);
}
}
onceperrequestfilter
Create a class that validates jwt that inherits from.
JwtAuthenticationFilter.java
public class JwtAuthorizationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain)
throws ServletException, IOException {
String header = req.getHeader("Authorization");
if (header == null || !header.startsWith("Bearer ")) {
//Continues processing, but does not set the credentials in the SecurityContext, resulting in a 403 return
chain.doFilter(req, res);
return;
}
//If it is a Bearer Prefix in the Authorization header
UsernamePasswordAuthenticationToken authentication = getAuthentication(req);
if (Objects.isNull(authentication)) {
chain.doFilter(req, res);
return;
}
SecurityContextHolder.getContext().setAuthentication(authentication);
chain.doFilter(req, res);
}
private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
String token = request.getHeader("Authorization");
if (token == null || !token.startsWith("Bearer ")) {
return null;
}
token = token.substring("Bearer ".length());
if (Objects.isNull(token) || token.length() == 0) {
return null;
}
JWTVerifier verifier = JWT.require(Algorithm.HMAC512("secret")).build();
try {
DecodedJWT jwt = verifier.verify(token);
return new UsernamePasswordAuthenticationToken(
jwt.getClaim("(C)").asString(), null,
null);
} catch (JWTDecodeException e) {
return null;
}
}
}
SecurityConfig.java
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login")
.permitAll()
.anyRequest()
.authenticated();
http.csrf().disable();
http.addFilter(getJsonAuthenticationFilter());
}
private JsonAuthenticationFilter getJsonAuthenticationFilter() throws Exception {
JsonAuthenticationFilter filter = new JsonAuthenticationFilter();
//Use default authentication method
filter.setAuthenticationManager(authenticationManager());
//Specify the path where the Filter will be executed and the HTTP method
filter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login", "POST"));
return filter;
}
}
Recommended Posts