赞
踩
几乎每个信息系统都需要认证授权保障其可靠性和安全性,当我们用spring框架开发时,Spring Security是一个不错的选择。
Spring Security是一个专注于为Java应用程序提供身份认证和授权功能的强大框架。它基于Spring框架,并提供了全面的安全服务集成,包括认证(Authentication)、授权(Authorization)、攻击防护和会话管理等功能。
在项目中新建一个springboot工程,并创建controller类定义接口
- @Slf4j
- @RestController
- @RequestMapping("/auth")
- public class LoginController {
-
- @RequestMapping("/login-success")
- public String loginSuccess() {
-
- return "登录成功";
- }
-
- @RequestMapping("/r/r1")
- public String r1() {
- return "访问r1资源";
- }
-
- @RequestMapping("/r/r2")
- public String r2() {
- return "访问r2资源";
- }
- }
启动服务,此时我们可以 在浏览器中访问http://localhost:63070/auth/login-success和http://localhost:63070/auth/r/r1,结果如下
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-security</artifactId>
- </dependency>
此时再次访问http://localhost:63070/auth/r/r1时,会自动进入/login登录页面,要先登录才能访问/r/r1资源。
/login是spring security提供的,加载可能较慢。
默认用户名user,每次启动服务时密码会自动重新生成并在控制台输出
1.自定义配置类继承WebSecurityConfigurerAdapter配置类
2.通过重写 configure(HttpSecurity http)
方法来定义安全规则和访问控制。
注意:NoOpPasswordEncoder
通常用于测试或者开发环境中,因为它并不会对密码进行任何加密,而是将密码以明文的形式存储和验证。存在严重的安全风险,因为密码可以很容易地被窃取和滥用。建议不要在生产环境中使用类似的明文密码存储方式。
- @EnableWebSecurity
- @EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
- public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
- @Bean
- public UserDetailsService userDetailsService(){
- //这里配置用户信息,这里暂时使用这种方式将用户存储在内存中
- InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
- manager.createUser(User.withUsername("xiyangyang").password("123").authorities("p1").build());
- manager.createUser(User.withUsername("meiyangyang").password("456").authorities("p2").build());
- return manager;
- }
-
- //获取一个密码编码器对象
- @Bean
- public PasswordEncoder passwordEncoder(){
- //密码为明文方式
- return NoOpPasswordEncoder.getInstance();
- }
-
- //配置安全拦截机制
- @Override
- protected void configure(HttpSecurity http) throws Exception{
- http.authorizeRequests()
- .antMatchers("/r/**").authenticated()//访问/r开始的请求需要认证通过
- .anyRequest().permitAll()//其它请求全部放行
- .and()
- .formLogin().successForwardUrl("/login-success");//登录成功跳转到/login-success
- http.logout().logoutUrl("/logout");//退出地址
- }
- }
此时便可以用自定义的用户名和密码登录访问服务
OAuth 2(Open Authorization 2)是一种授权框架,允许第三方应用程序通过使用授权服务器进行限制的方式,访问受保护的资源,而无需用户将其凭据直接提供给第三方应用程序。它在网络服务之间提供了安全的授权标准。
OAuth 2.0 是一个开放的标准,被广泛接受和支持。许多大型的互联网服务提供商和平台都实现了 OAuth 2.0,使得开发者可以使用统一的协议和工具来实现授权流程,而无需为每个服务提供商单独开发授权机制。我们熟知的微信扫码就是基于这种OAuth2协议实现的
Spring Security支持OAuth2认证,OAuth2提供授权码模式、密码模式、简化模式、客户端模式等授权模式,微信扫码登录就是基于授权码模式,其中授权码模式和密码模式应用较多,下面使用Spring Security演示授权码模式、密码模式
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-oauth2</artifactId>
- </dependency>
AuthenticationManager
的实例在之前创建的WebSecurityConfig 中注入AuthenticationManager
,以支持身份验证功能
- public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
- @Bean
- public AuthenticationManager authenticationManagerBean() throws Exception {
- return super.authenticationManagerBean();
- }
- }
@EnableAuthorizationServer 注解标识并继承AuthorizationServerConfigurerAdapter来配置OAuth2.0 授权服务器
- @Configuration
- @EnableAuthorizationServer
- public class AuthorizationServer extends AuthorizationServerConfigurerAdapter {
-
- @Resource(name="authorizationServerTokenServicesCustom")
- private AuthorizationServerTokenServices authorizationServerTokenServices;
-
- @Autowired
- private AuthenticationManager authenticationManager;
-
- //客户端详情服务
- @Override
- public void configure(ClientDetailsServiceConfigurer clients)
- throws Exception {
- clients.inMemory()// 使用in-memory存储
- .withClient("baidu")// client_id
- .secret("baidu")//客户端密钥
- // .secret(new BCryptPasswordEncoder().encode("XcWebApp"))//客户端密钥
- .resourceIds("baidu-resource")//资源列表
- // 该client允许的授权类型authorization_code,password,refresh_token,implicit,client_credentials
- .authorizedGrantTypes("authorization_code", "password","client_credentials","implicit","refresh_token")
- .scopes("all")// 允许的授权范围
- .autoApprove(false)//false跳转到授权页面
- //客户端接收授权码的重定向地址
- .redirectUris("http://www.baidu.com")
- ;
- }
-
- //令牌端点的访问配置
- @Override
- public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
- endpoints
- .authenticationManager(authenticationManager)//认证管理器
- .tokenServices(authorizationServerTokenServices)//令牌管理服务
- .allowedTokenEndpointRequestMethods(HttpMethod.POST);
- }
-
- //令牌端点的安全配置
- @Override
- public void configure(AuthorizationServerSecurityConfigurer security){
- security
- .tokenKeyAccess("permitAll()") //oauth/token_key是公开
- .checkTokenAccess("permitAll()") //oauth/check_token公开
- .allowFormAuthenticationForClients() //表单认证(申请令牌)
- ;
- }
-
- }
4.2新建令牌配置类
- @Configuration
- public class TokenConfig {
-
- @Autowired
- TokenStore tokenStore;
-
- @Bean
- public TokenStore tokenStore() {
- //使用内存存储令牌(普通令牌)
- return new InMemoryTokenStore();
- }
-
- //令牌管理服务
- @Bean(name="authorizationServerTokenServicesCustom")
- public AuthorizationServerTokenServices tokenService() {
- DefaultTokenServices service=new DefaultTokenServices();
- service.setSupportRefreshToken(true);//支持刷新令牌
- service.setTokenStore(tokenStore);//令牌存储策略
- service.setAccessTokenValiditySeconds(7200); // 令牌默认有效期2小时
- service.setRefreshTokenValiditySeconds(259200); // 刷新令牌默认有效期3天
- return service;
- }
-
- }
启动服务,登录成功后在浏览器输入以下地址:
注意:我们在AuthorizationServer已经配置好了以下参数
解释:
client_id:客户端的唯一标识符
response_type:授权码模式固定为code。
scope:客户端权限。
redirect_uri:跳转uri,当授权码申请成功后会跳转到此地址,并在后边带上code参数(授权码)
此时会出现以下界面选择approve,点击authorize则会跳转到百度页面
我们可以看到地址为https://www.baidu.com/?code=Rd8kGZ,此时便可以拿到授权码Rd8kGZ
注意:授权码只能使用一次。
拿到授权码后,使用postman或者httpclient执行
注意更改code为=Rd8kGZ
POST localhost:63070/auth/oauth/token?client_id=baidu&client_secret=baidu&grant_type=authorization_code&code=Rd8kGZ&redirect_uri=http://www.baidu.com
此时申请令牌成功
解释:
access_token:这是一个访问令牌,用于客户端在访问受保护的资源时进行身份验证和授权。
token_type:指定了访问令牌的类型,这里是 bearer。是OAuth 2.0中定义的一种令牌类型,表示客户端可以使用令牌来访问被授权的资源。
refresh_token:刷新令牌,用于获取新的访问令牌。刷新令牌有更长的有效期,用于在访问令牌过期时获取新的访问令牌。
expires_in:
表示访问令牌的有效期限(秒)。
scope:指定了授权的范围,all 表示这个访问令牌被授予了访问所有资源的权限。
密码模式相对授权码模式简单,不需要借助浏览器。
可以直接postman或者httpclient执行
POST localhost:63070/auth/oauth/token?client_id=baidu&client_secret=baidu&grant_type=password&username=xiyangyang&password=123
解释:
client_id=baidu: 这是客户端的唯一标识符。
client_secret=baidu: 客户端的密钥,用于对客户端的身份进行验证。
grant_type=password: 指定了密码授权模式。
username=xiyangyang: 用户名
password=123: 用户密码
执行输出:
注意:密码模式十分简单,但却意味着将用户敏感信息泄露给了client,建议仅在确保安全的环境下使用。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。