本节将介绍基于Spring Security实现的基本认证及OAuth2。
如果Spring Security位于类路径上,则所有HTTP端点上默认使用基本认证,这样就能使Web应用程序得到一定的安全保障。最为快捷的方式是在依赖中添加Spring Boot Security Starter。
//依赖关系dependencies {//该依赖用于编译阶段compile('org.springf ramework . boot : spring-boot-starter-security')
如果要向Web应用程序添加方法级别的安全保障,还可以在Spring Boot应用里面添加@ Ena-bleGlobalMethodSecurity注解来实现,如下面的例子所示。
@EnableGlobalMe thodsecurity@SpringBootApplicationpublic class Application {public static void main (String[] args) {SpringApplication. run (Application.class, args) ;
需要注意的是,@ EnableGlobalMethodSecurity 可以配置多个参数:
prePostEnabled:决定Spring Security的前注解是否可用@PreAuthorize、@PostAuthorize 等;
secureEnabled:决定Spring Security的保障注解@Secured是否可用;
jsr250Enabled :决定JSR-250注解@RolesAllowed等是否可用。
配置方式分别如下。
@EnableGlobalMethodSecurity (securedEnabled = true)public class MethodSecuri tyConfig {// ...@EnableGlobalMethodSecurity (jsr250Enabled = true)public class MethodSecurityConfig {//...@EnableGlobalMe thodsecurity (prePostEnabled = true)public class MethodSecurityConfig {
/...
}
在同一个应用程序中,可以启用多个类型的注解,但是对于行为类的接口或类只应该设置一个注解。如果将2个注解同时应用于某- -特定方法, 则只有其中-一个被应用。
1. @Secured
此注解是用来定义业务方法的安全配置属性的列表。您可以在需要安全角色1权限等的方法上指定@Secured,并且只有那些角色1权限的用户才可以调用该方法。如果有人不具备要求的角色1权限但试图调用此方法,将会抛出AccessDenied 异常。
@Secured源于Spring 之前的版本,它有一个局限就是不支持Spring EL表达式。可以看看下面的例子。
如果你想指定AND (和)这个条件,即deleteUser方法只能被同时拥有ADMIN & DBA,但是仅仅通过使用@Secured注解是无法实现的。
但是你可以使用Spring新的注解@PreAuthorize/@PostAuthorize (支持Spring EL),使实现上面的功能成为可能,而且无限制。
@PreAuthori ze/@PostAuthorize
Spring的@PreAuthorize/@PostAuthorize 注解更适合方法级的安全,也支持Spring EL表达式
语言,提供了基于表达式的访问控制。
●@PreAuthorize 注解:适合进入方法前的权限验证,@PreAuthorize 可以将登录用户的角色1权
限参数传到方法中。
●@PostAuthorize注解:使用并不多,在方法执行后再进行权限验证。
以下是-一个使用了@PreAuthorize 注解的例子。
@PreAuthorize ("hasAuthority('ROLE ADMIN')") // 指定角色权限才能操作方法@GetMapping(value = "delete/ {id}")
public ModelAndView delete (@PathVariable ("id") Long id, Model model) {userService. removeUser (id) ;model . addAttribute ("userList", userService. listUsers()) ;model. addAttribute("title", "删除用户");return new ModelAndView ("users/list", "userModel", model) ;}
2.登录账号和密码
默认的AuthenticationManager具有单个用户账号,其中用户名称是“user",密码是一个随机码,在应用程序启动时以INFO级别打印,如下所示。
Using default security password: fa195d-3f4c-48b1-ad50-e24c31d5cf36
当然,你也可以在配置文件中来自定义用户名和密码。
security . user . name=guest
security. user . password=guest123
如果您的类路径中有spring-security-oauth2, 则可以利用某些自动配置来轻松设置授权或资源服务器,即可实现OAuth2认证。
1.什么是OAuth 2.0
OAuth 2.0的规范可以参考RFC 6749 ( ht:t/ols.ietf.org/htm/fc6749 )。
OAuth是一个开放标准,允许用户让第三方应用访问该用户在某- -网站上存储的私密的资源(如照片、视频、联系人列表等),而无须将用户名和密码提供给第三方应用。目前,OAuth的最新版本为2.0。
OAuth允许用户提供-一个令牌 ,而不是用户名和密码来访问他们存放在特定服务提供者的数据。
每一个令牌授权一个特定的网站(例如,视频编辑网站)在特定的时段(例如,接下来的2小时内)内访问特定的资源(例如,仅仅是某一.相册中的视频) 。这样, OAuth允许用户授权第三方网站访问他们存储在另外的服务提供者上的信息,而不需要分享它们的访问许可或数据的所有内容。
2. OAuth 2.0的核心概念
0Auth2.0主要有以下4类角色。.
resource owner:
资源所有者,指终端的“用户”( user )
resource server:资源服务器,即服务提供商存放受保护资源。访问这些资源,需要获得访问令牌( Access Token)。它与认证服务器可以是同一台服务器,也可以是不同的服务器。如果我们访问新浪博客网站,那么如果使用新浪博客的账号来登录新浪博客网站,那么新浪博客的资源和新浪博客的认证都是同- -家,可以认为是同一个服务器。如果我们使用新浪博客账号去登录知乎,那么显然知乎的资源和新浪的认证不是-一个服务器。
client:客户端,代表向受保护资源进行资源请求的第三方应用程序。
authorization server : .
授权服务器,在验证资源所有者并获得授权成功后,将发放访问令牌给客户端。
3. OAuth 2.0的认证流程
OAuth 2.0的认证流程如下。
①用户打开客户端以后,客户端请求资源所有者(用户)的授权。
②用户同意给予客户端授权。
③客户端使用上一步获得的授权,向认证服务器申请访问令牌。
④认证服务器对客户端进行认证以后,确认无误,同意发放访问令牌。
⑤客户端使用访问令牌,向资源服务器申请获取资源。
⑥资源服务器确认令牌无误,同意向客户端开放资源。
其中,用户授权有以下4种模式:
授权码模式( authorization code) ;
简化模式( implicit) ;
密码模式( resource owner password credentials) ;
客户端模式( client credentials)。
4.配置
项目的核心配置如下。
github. cl ient. clientId=ad2abbc19b6c5f0ed117gi thub. client. clientSecret=26db88a4dfc34cebaf196e68761c1294ac4ce265gi thub.c1 ient. accessTokenUri=https://gi thub. com/1ogin/ oauth/access_tokengithub. client .userAuthorizationUri=https:/ /github. com/ login/ oauth/authorizegi thub. client.clientAuthenticationScheme-form gi thub. client. tokenName=oauth_ tokengithub. client.authenticationScheme=querygi thub. resource .userInfoUri=https:/ /api .github. com/user
包括了作为一个client所需要的大部分参数。其中clientId、 clientSecret 是在GitHub注册一个应用时生成的。如果读者不想注册应用,则可以直接使用上面的配置。如果要注册,则文章最后有注册流程。
5.项目安全的配置
安全配置中需要加上@EnableWebSecurity、@EnableOAuth2Client 注解,来启用Web安全认证机制,并表明这是一个OAuth 2.0客户端。@EnableGlobalMethodScurity 注明,项目采用了基于方法的安全设置。
@EnableWebSecurity@EnableOAuth2Client//启用0Auth2.0客户端@EnableGlobalMethodSecurity (prePostEnabledtrue)
启用方法安全设置
public class SecurityConfig extends WebSecurityConfigurerAdapter {//...}
使用Spring Security,我们需要继承org. springframework. security config. antationweb.configura-tion. WebSecurityConfigurerAdapter并重写以下configure 方法。
@Override
protected void configure (HttpSecurity http) throws Exception {
http. addFilterBefore (ssoFilter(), BasicAuthenticationFilter.class). antMatcher ("/**")
. authori zeRequests ()
. antMatchers("/", "/index", "/403", "/css/**", "/js/**", "/
fonts/**") .permitAll() //不设限制,都允许访问
. anyRequest ()
. authenticated()
.and() .logout () . logoutSuccessUrl ("/") . permitAll ()
.and() .csrf () . csrfTokenRepository (CookieCsrfTokenRepository.
wi thHttpOnlyFalse() )
上面的配置是设置了一些过滤策略,除了静态资源及不需要授权的页面,我们允许访问其他的资源,都需要授权访问。
其中,我们也设置了一个过滤器ssoFiter,用于在BasicAuthenticationFilter之前进行拦截。如果拦截到的是/login,就是访问认证服务器。private Filter ssoFilter () {
OAuth2ClientAuthenticationProcessingFilter githubFilter = new OAu-
th2ClientAuthenticationProcessingFilter ("/login") ;
OAuth2RestTemplate githubTemplate = new OAuth2Res tTemplate (github(),
oauth2Cl ientContext) ;
gi thubFilter. setRestTemplate (gi thubTemplate) ;
UserInfoTokenServices tokenServices = new UserInfoTokenServices
(githubResource () .getUserInfoUri (),github() .getClientId());
tokenServices. setRestTemplate (githubTemplate) ;
githubFilter. setTokenServices (tokenServices) ;return githubFilter;@Beanpublic FilterRegistrationBean oauth2C1 ientFilterRegistration (
OAuth2ClientContextFilter filter) {
FilterRegistrationBean registration = new FilterRegistrationBean() ;
registration.setFilter (filter) ;
registration. setOrder(-) ;return registration;@Bean@ConfigurationProperties ("github. client")public AuthorizationCodeResourceDetails github() {return new Authori zationCodeResourceDetails () ;@Bean@ConfigurationProperties ("gi thub . resource")public ResourceServerProperties gi thubResource() {return new ResourceServerProperties() ;
6.资源服务器
我们写了两个控制器来提供相应的资源。
一个控制器是MainController.java。代码如下。
@Controllerpublic class MainController {@GetMapping("/")public String root ()return "redirect: / index";@GetMapping ("/index")public String index (Principal principal, Model model) {if (principal == null ) {return "index";
System. out.println (principal. toString()) ;
model . addAttribute ("principal", principal) ;return "index";@GetMapping ("/403")public String accesssDenied() {return "403";
}
}
在index页面如果认证成功,将会显示一些认证信息。
另一个控制器是UserContrllerjava,用来模拟用户管理的相关资源。
@RestController
@RequestMapping("/")public class UserController/**
*查询所用用户return@GetMapping(" /users")CPreAuthorize ("hasAuthority('ROLE_ USER')") // 指定角色权限才能操作方法public ModelAndView list (Model model) {List<User> list = new ArrayList<>() ; //当前所在页面数据列表list. add (new User ("waylau",)) ;list.add (new User("老卫",)) ;
model. addAttribute ("title", "用户管理") ;
model. addAttribute ("userList", list) ;return new ModelAndView ("users/list", "userModel", model) ;
}
7.前端页面
页面主要是采用Thymeleaf及Bootstrap来编写的。
首页用于显示用户的基本信息。<body><div class="container"><div class="mt-3"><h2>He1l1o Spring Security</h2></div><div sec: authori ze=" isAuthenticated()" th:if="${principal}" th:-object="${principal}"><p>已有用户登录</p><p>登录的用户为: <span sec: authentication="name"></span></p><p>用户权限为: <span th: text="* {userAuthentication. authori-
ties}"></span></p><p>用户头像为: <img alt="" class="avatar width-full rounded-
2" height="230"th:src="* {userAuthentication.details.avatar_ url}"width="230"></p></div><div sec: authori ze="i sAnonymous () "><p>未有用户登录</p></div></div></body>用户管理界面显示用户的列表。<body><div class="container"><div class="mt-3"><h2 th:text="$ {userModel. title} ">Welcome to waylau. com</h2></div><table class="table table-hover"><thead><tr><td>Age</td><td>Name</td><td sec :authorize="hasRole (' ADMIN') ">Operation</td></tr></ thead><tbody><tr th:if="$ {userModel.userList.size() } eq 0"><td colspan="3">没有用户信息! ! </td></tr><tr th:each="user : $ {userModel .userList}"><td th:text="${user.age}">11</td><td th: text="$ {user . name}">waylau</a></td><td sec:authorize="hasRole(' ADMIN')"><div >我是管理员</div></td></tr></ tbody></ table></body>
8.运行效果
图3-3展示的是没有授权访问首页。
当我们单击“登录”按钮时,会重定向到GitHub,登录界面并进行授权,如图3-4所示。
图3-5展示的是授权后的首页。
授权后就能进入用户管理界面,如图3-6所示。
9.注册GitHub应用
如果需要注册,请根据下面的流程来生成Client ID和Client Secret。
访问 htpt:p:/itb.co/ettings/applications/new,注册应用,生成客户端ID和密码。比如,
Client ID : ad2abbc1 9b6c5f0ed117Client Secret : 6db88a4dfc34cebaf196e68761c1294ac4ce265
将客户端ID和密码写入程序配置即可。图3-7展示了注册应用信息的界面。
感谢大家的支持!!!
下篇给大家介绍的内容是如何在 Spring Boot应用中,实现跨域访问资源~~
本文就是愿天堂没有BUG给大家分享的内容,大家有收获的话可以分享下,想学习更多的话可以到微信公众号里找我,我等你哦。