springboot集成springsecurity使⽤OAUTH2做权限管理的教程Spring Security OAuth2
主要配置,注意l最后的配置resource filter顺序配置,不然会能获取token但是访问⼀直没有权限WebSecurityConfigurerAdapter 所在服务器的web配置
AuthorizationServerConfigurerAdapter 认证服务器配置
ResourceServerConfigurerAdapter 资源服务器配置这两个配置在 OAuth2Config.java
权限有⼏种模式:“authorization_code”, “client_credentials”, “refresh_token”, “password”, “implicit”,是在请求token时的当grant_type值启动项⽬后:通过controller⽅法上的注解@PreAuthorize,设置权限⾓⾊
//获取token,password模式,个⼈ccc的权限,
localhost:8080/oauth/token?username=ccc&password=456&grant_type=password&scope=test&client_id=client_1&client_secret=123456
//check token
localhost:8080/oauth/check_token?token=02b2d1ac-2f8d-42b6-8e04-c47ed3601249
//access_denied
localhost:8080/add?access_token=792e1bea-78b8-4a36-bfa8-3b72f1759438
//没加token,禁⽌
127.0.0.1:8080
/
/其他访问需要access_token
127.0.0.1:8080?access_token=7357c921-0561-42bd-b02a-2d4a049cf69e
localhost:8080/list?access_token=2a06c35f-0758-48c7-904e-4db5bc7b2b83
项⽬结构:
Spring Security OAuth2 demo
//Controller.java
package boottest.auth;
import org.springframework.security.access.prepost.PreAuthorize;
import org.Authentication;
import org.authority.SimpleGrantedAuthority;
import org.ontext.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
/**
* @author zhanghui
* @date 2019/4/24
*/
@RestController
@ResponseBody
public class Controller {
@GetMapping(value = {"/",""})
public String defaut(){
return "defaut";
}
@GetMapping("/index")
public String index(){
return "index";
}
// direct request to "/logout" for logout
@RequestMapping("/login")
public String login(){
return "<form action=\"/login\" method=\"post\">\n" +
" <label for=\"username\">Username</label>:\n" +
" <input type=\"text\" id=\"username\" name=\"username\" autofocus=\"autofocus\" /> <br />\n" + " <label for=\"password\">Password</label>:\n" +
" <input type=\"password\" id=\"password\" name=\"password\" /> <br />\n" +
" <input type=\"submit\" value=\"Login\" />\n" +
"</form>";
}
@GetMapping("/login-error")
public String loginerror(){
return "login-error";
}
@PreAuthorize("hasAuthority('ROLE_user')") //判断⾓⾊
// @PreAuthorize("hasRole('user')") //同上,判断⾓⾊,会⾃动加前缀 ROLE_
@GetMapping("/list")
public String list() {
//程序内判断role
Authentication authentication = Context().getAuthentication();
Authorities().contains(new SimpleGrantedAuthority("ROLE_user"))){
System.out.println("user role2");
}
return "to list";
}
@PreAuthorize("hasAuthority('ROLE_admin')")
@GetMapping("/add")
public String add() {
return "to add";
}
}
//MyUserDetailsService.java
package boottest.auth;
import org.GrantedAuthority;
import org.authority.AuthorityUtils;
import org.userdetails.User;
import org.userdetails.UserDetails;
import org.userdetails.UserDetailsService;
import org.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author zhanghui
* @date 2019/4/24
*/
@Service
public class MyUserDetailsService implements UserDetailsService {
/
**
* 根据⽤户的⾓⾊判断权限
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//模拟数据库
SysUser sysUser;
//password need BCrypt ,/projects/jBCrypt/, BCrypt.java
if("abc".equals(username)){
sysUser=new SysUser("abc",BCrypt.hashpw("123", salt()),"ROLE_admin,ROLE_user");
}else if("ccc".equals(username)){
sysUser=new SysUser("ccc",BCrypt.hashpw("456", salt()), "ROLE_user");
}else {
sysUser=null;
}
if (null == sysUser) {
throw new UsernameNotFoundException(username);
}
// authorities 是 roles 集合
List<GrantedAuthority> authorities = Roles());
//上⾯是根据⽤户名查出⽤户信息,下⾯才会⽐较传来的password是否正确
return new UserName(), Password(), authorities);
}
}
//OAuth2Config.java
package boottest.auth;
import org.springframework.beans.factory.annotation.Autowired;
import t.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.fig.annotation.web.builders.HttpSecurity;
import org.fig.http.SessionCreationPolicy;
import org.springframework.figurers.ClientDetailsServiceConfigurer;
import org.springframework.fig.figuration.AuthorizationServerConfigurerAdapter; import org.springframework.fig.figuration.EnableAuthorizationServer;
import org.springframework.fig.figuration.EnableResourceServer;
import org.springframework.fig.figuration.ResourceServerConfigurerAdapter; import org.springframework.fig.figurers.AuthorizationServerEndpointsConfigurer; import org.springframework.fig.figurers.AuthorizationServerSecurityConfigurer; import org.springframework.fig.figurers.ResourceServerSecurityConfigurer; import org.springframework.security.ken.store.InMemoryTokenStore;
/**
* @author zhanghui
* @date 2019/4/25
*/
@Configuration
public class OAuth2Config {
//认证服务器
@Configuration
@EnableAuthorizationServer
class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter{
@Autowired
AuthenticationManager authenticationManager;
@Autowired
private MyUserDetailsService myUserDetailsService;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
//当grant_type=password 获取token,token的权限是password⼈的⾓⾊权限
//当grant_type=client_credentials 获取token, token的权限是下⾯配置的client的权限authorities
clients.inMemory()
.withClient("client_1")
.authorizedGrantTypes("authorization_code", "client_credentials", "refresh_token", "password", "implicit") .authorities("ROLE_user")
.scopes("test")
.resourceIds("rId1")
.secret("123456");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
.authenticationManager(authenticationManager)
.userDetailsService(myUserDetailsService);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.allowFormAuthenticationForClients()
.
checkTokenAccess("permitAll()"); // for /oauth/check_token
}
}
//资源服务器
@Configuration
@EnableResourceServer
class ResourceServerConfiguration extends ResourceServerConfigurerAdapter{
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
// Since we want the protected resources to be accessible in the UI as well we need
// session creation to be allowed (it's disabled by default in 2.0.6)
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and()
.authorizeRequests().anyRequest().authenticated();
// .and()
// .anonymous()
// .and()
/
/ .authorizeRequests()
// .antMatchers("/list").access("#oauth2.hasScope('test') and hasRole('ROLE_user')")
.antMatchers("/add").access("hasRole('ROLE_admin')");//配置访问控制,必须认证过后才可以访问
// .antMatchers("/add").authenticated();//配置访问控制,必须认证过后才可以访问
// @formatter:on
}
}
}
//SecurityConfig.java
package boottest.auth;
import org.springframework.beans.factory.annotation.Autowired;
import t.annotation.Bean;
import t.annotation.Configuration;
import org.fig.annotation.authentication.builders.AuthenticationManagerBuilder; import org.figuration.EnableGlobalMethodSecurity; import org.fig.annotation.web.builders.HttpSecurity;
import org.fig.figuration.EnableWebSecurity;
import org.fig.figuration.WebSecurityConfigurerAdapter; import org.pto.bcrypt.BCryptPasswordEncoder;
import org.pto.password.PasswordEncoder;
/**
* @author zhanghui
* @date 2019/4/24
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) // 启⽤⽅法级别的权限认证
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MyUserDetailsService myUserDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
// 允许所有⽤户访问"/"和"/index.html"
http
.requestMatchers().anyRequest()
.and()
.authorizeRequests()
.antMatchers("/oauth/**").permitAll();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myUserDetailsService).passwordEncoder(passwordEncoder());
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
//SysUser.java
package boottest.auth;
/**
* @author zhanghui
* @date 2019/4/24
*/
springboot结构public class SysUser {
private String userName;
private String password;
private String roles;
public SysUser(String userName, String password, String roles) {
this.userName = userName;
this.password = password;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getRoles() {
return roles;
}
public void setRoles(String roles) {
}
}
//l
server:
port: 8080
springframework.web: DEBUG
# spring security和oauth2的资源控制互相覆盖,⽆法同时⽣效, 覆盖后,ResourceServer 因缺失配置不能验证token,导致错误,虽然能获取token,但是权限访问失败security:
oauth2:
resource:
filter-order: 3
//BCrypt.java
// Copyright (c) 2006 Damien Miller <>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
/
/ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package boottest.auth;
import java.io.UnsupportedEncodingException;
import java.security.SecureRandom;
/**
* BCrypt implements OpenBSD-style Blowfish password hashing using
* the scheme described in "A Future-Adaptable Password Scheme" by
* Niels Provos and David Mazieres.
* <p>
* This password hashing system tries to thwart off-line password
* cracking using a computationally-intensive hashing algorithm,
* based on Bruce Schneier's Blowfish cipher. The work factor of
* the algorithm is parameterised, so it can be increased as
* computers get faster.
* <p>
* Usage is really simple. To hash a password for the first time,
* call the hashpw method with a random salt, like this:
* <p>
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论